source: CLRX/CLRadeonExtender/trunk/amdasm/AsmPseudoOps.cpp @ 2584

Last change on this file since 2584 was 2584, checked in by matszpk, 4 years ago

CLRadeonExtender: AsmROCm: Add ROCmKernelConfig to Kernelstate
Asm: add ROCm support (add pseudo-ops and format handling). fixed checkPseudoOpName (add AmdCL2 pseudo-op checking).

File size: 96.5 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <string>
22#include <cstring>
23#include <cassert>
24#include <fstream>
25#include <vector>
26#include <stack>
27#include <set>
28#include <utility>
29#include <algorithm>
30#include <CLRX/utils/Utilities.h>
31#include <CLRX/amdbin/AmdBinaries.h>
32#include <CLRX/amdbin/GalliumBinaries.h>
33#include <CLRX/utils/MemAccess.h>
34#include <CLRX/utils/GPUId.h>
35#include <CLRX/utils/InputOutput.h>
36#include <CLRX/amdasm/Assembler.h>
37#include "AsmInternals.h"
38
39using namespace CLRX;
40
41// pseudo-ops used while skipping clauses
42static const char* offlinePseudoOpNamesTbl[] =
43{
44    "else", "elseif", "elseif32", "elseif64", "elseifarch",
45    "elseifb", "elseifc", "elseifdef",
46    "elseifeq", "elseifeqs", "elseiffmt",
47    "elseifge", "elseifgpu", "elseifgt",
48    "elseifle", "elseiflt", "elseifnarch", "elseifnb", "elseifnc",
49    "elseifndef", "elseifne", "elseifnes",
50    "elseifnfmt", "elseifngpu", "elseifnotdef",
51    "endif", "endm", "endr",
52    "if", "if32", "if64", "ifarch", "ifb", "ifc", "ifdef", "ifeq",
53    "ifeqs", "iffmt", "ifge", "ifgpu", "ifgt", "ifle",
54    "iflt", "ifnarch", "ifnb", "ifnc", "ifndef",
55    "ifne", "ifnes", "ifnfmt", "ifngpu", "ifnotdef",
56    "irp", "irpc", "macro", "rept"
57};
58
59/// pseudo-ops not ignored while putting macro content
60static const char* macroRepeatPseudoOpNamesTbl[] =
61{
62    "endm", "endr", "irp", "irpc", "macro", "rept"
63};
64
65// pseudo-ops used while skipping clauses
66enum
67{
68    ASMCOP_ELSE = 0, ASMCOP_ELSEIF, ASMCOP_ELSEIF32, ASMCOP_ELSEIF64, ASMCOP_ELSEIFARCH,
69    ASMCOP_ELSEIFB, ASMCOP_ELSEIFC, ASMCOP_ELSEIFDEF,
70    ASMCOP_ELSEIFEQ, ASMCOP_ELSEIFEQS, ASMCOP_ELSEIFFMT,
71    ASMCOP_ELSEIFGE, ASMCOP_ELSEIFGPU, ASMCOP_ELSEIFGT,
72    ASMCOP_ELSEIFLE, ASMCOP_ELSEIFLT, ASMCOP_ELSEIFNARCH, ASMCOP_ELSEIFNB, ASMCOP_ELSEIFNC,
73    ASMCOP_ELSEIFNDEF, ASMCOP_ELSEIFNE, ASMCOP_ELSEIFNES,
74    ASMCOP_ELSEIFNFMT, ASMCOP_ELSEIFNGPU, ASMCOP_ELSEIFNOTDEF,
75    ASMCOP_ENDIF, ASMCOP_ENDM, ASMCOP_ENDR,
76    ASMCOP_IF, ASMCOP_IF32, ASMCOP_IF64, ASMCOP_IFARCH, ASMCOP_IFB,
77    ASMCOP_IFC, ASMCOP_IFDEF, ASMCOP_IFEQ,
78    ASMCOP_IFEQS, ASMCOP_IFFMT, ASMCOP_IFGE, ASMCOP_IFGPU, ASMCOP_IFGT, ASMCOP_IFLE,
79    ASMCOP_IFLT, ASMCOP_IFNARCH, ASMCOP_IFNB, ASMCOP_IFNC, ASMCOP_IFNDEF,
80    ASMCOP_IFNE, ASMCOP_IFNES, ASMCOP_IFNFMT, ASMCOP_IFNGPU, ASMCOP_IFNOTDEF,
81    ASMCOP_IRP, ASMCOP_IRPC, ASMCOP_MACRO, ASMCOP_REPT
82};
83
84/// pseudo-ops not ignored while putting macro content
85enum
86{ ASMMROP_ENDM = 0, ASMMROP_ENDR, ASMMROP_IRP, ASMMROP_IRPC, ASMMROP_MACRO, ASMMROP_REPT };
87
88/// all main pseudo-ops
89static const char* pseudoOpNamesTbl[] =
90{
91    "32bit", "64bit", "abort", "align", "altmacro",
92    "amd", "amdcl2", "arch", "ascii", "asciz",
93    "balign", "balignl", "balignw", "buggyfplit", "byte",
94    "data", "double", "else",
95    "elseif", "elseif32", "elseif64",
96    "elseifarch", "elseifb", "elseifc", "elseifdef",
97    "elseifeq", "elseifeqs", "elseiffmt",
98    "elseifge", "elseifgpu", "elseifgt",
99    "elseifle", "elseiflt", "elseifnarch", "elseifnb",
100    "elseifnc", "elseifndef", "elseifne", "elseifnes",
101    "elseifnfmt", "elseifngpu", "elseifnotdef",
102    "end", "endif", "endm",
103    "endr", "equ", "equiv", "eqv",
104    "err", "error", "exitm", "extern",
105    "fail", "file", "fill", "fillq",
106    "float", "format", "gallium", "global",
107    "globl", "gpu", "half", "hword", "if", "if32", "if64",
108    "ifarch", "ifb", "ifc", "ifdef", "ifeq",
109    "ifeqs", "iffmt", "ifge", "ifgpu", "ifgt", "ifle",
110    "iflt", "ifnarch", "ifnb", "ifnc", "ifndef",
111    "ifne", "ifnes", "ifnfmt", "ifngpu", "ifnotdef", "incbin",
112    "include", "int", "irp", "irpc", "kernel", "lflags",
113    "line", "ln", "local", "long",
114    "macro", "main", "noaltmacro",
115    "nobuggyfplit", "octa", "offset", "org",
116    "p2align", "print", "purgem", "quad",
117    "rawcode", "reg", "rept", "rocm", "rodata",
118    "sbttl", "section", "set",
119    "short", "single", "size", "skip",
120    "space", "string", "string16", "string32",
121    "string64", "struct", "text", "title",
122    "undef", "version", "warning", "weak", "word"
123};
124
125enum
126{
127    ASMOP_32BIT = 0, ASMOP_64BIT, ASMOP_ABORT, ASMOP_ALIGN, ASMOP_ALTMACRO,
128    ASMOP_AMD, ASMOP_AMDCL2, ASMOP_ARCH, ASMOP_ASCII, ASMOP_ASCIZ,
129    ASMOP_BALIGN, ASMOP_BALIGNL, ASMOP_BALIGNW, ASMOP_BUGGYFPLIT, ASMOP_BYTE,
130    ASMOP_DATA, ASMOP_DOUBLE, ASMOP_ELSE,
131    ASMOP_ELSEIF, ASMOP_ELSEIF32, ASMOP_ELSEIF64,
132    ASMOP_ELSEIFARCH, ASMOP_ELSEIFB, ASMOP_ELSEIFC, ASMOP_ELSEIFDEF,
133    ASMOP_ELSEIFEQ, ASMOP_ELSEIFEQS, ASMOP_ELSEIFFMT,
134    ASMOP_ELSEIFGE, ASMOP_ELSEIFGPU, ASMOP_ELSEIFGT,
135    ASMOP_ELSEIFLE, ASMOP_ELSEIFLT, ASMOP_ELSEIFNARCH, ASMOP_ELSEIFNB,
136    ASMOP_ELSEIFNC, ASMOP_ELSEIFNDEF, ASMOP_ELSEIFNE, ASMOP_ELSEIFNES,
137    ASMOP_ELSEIFNFMT, ASMOP_ELSEIFNGPU, ASMOP_ELSEIFNOTDEF,
138    ASMOP_END, ASMOP_ENDIF, ASMOP_ENDM,
139    ASMOP_ENDR, ASMOP_EQU, ASMOP_EQUIV, ASMOP_EQV,
140    ASMOP_ERR, ASMOP_ERROR, ASMOP_EXITM, ASMOP_EXTERN,
141    ASMOP_FAIL, ASMOP_FILE, ASMOP_FILL, ASMOP_FILLQ,
142    ASMOP_FLOAT, ASMOP_FORMAT, ASMOP_GALLIUM, ASMOP_GLOBAL,
143    ASMOP_GLOBL, ASMOP_GPU, ASMOP_HALF, ASMOP_HWORD, ASMOP_IF, ASMOP_IF32, ASMOP_IF64,
144    ASMOP_IFARCH, ASMOP_IFB, ASMOP_IFC, ASMOP_IFDEF, ASMOP_IFEQ,
145    ASMOP_IFEQS, ASMOP_IFFMT, ASMOP_IFGE, ASMOP_IFGPU, ASMOP_IFGT, ASMOP_IFLE,
146    ASMOP_IFLT, ASMOP_IFNARCH, ASMOP_IFNB, ASMOP_IFNC, ASMOP_IFNDEF,
147    ASMOP_IFNE, ASMOP_IFNES, ASMOP_IFNFMT, ASMOP_IFNGPU, ASMOP_IFNOTDEF, ASMOP_INCBIN,
148    ASMOP_INCLUDE, ASMOP_INT, ASMOP_IRP, ASMOP_IRPC, ASMOP_KERNEL, ASMOP_LFLAGS,
149    ASMOP_LINE, ASMOP_LN, ASMOP_LOCAL, ASMOP_LONG,
150    ASMOP_MACRO, ASMOP_MAIN, ASMOP_NOALTMACRO,
151    ASMOP_NOBUGGYFPLIT, ASMOP_OCTA, ASMOP_OFFSET, ASMOP_ORG,
152    ASMOP_P2ALIGN, ASMOP_PRINT, ASMOP_PURGEM, ASMOP_QUAD,
153    ASMOP_RAWCODE, ASMOP_REG, ASMOP_REPT, ASMOP_ROCM, ASMOP_RODATA,
154    ASMOP_SBTTL, ASMOP_SECTION, ASMOP_SET,
155    ASMOP_SHORT, ASMOP_SINGLE, ASMOP_SIZE, ASMOP_SKIP,
156    ASMOP_SPACE, ASMOP_STRING, ASMOP_STRING16, ASMOP_STRING32,
157    ASMOP_STRING64, ASMOP_STRUCT, ASMOP_TEXT, ASMOP_TITLE,
158    ASMOP_UNDEF, ASMOP_VERSION, ASMOP_WARNING, ASMOP_WEAK, ASMOP_WORD
159};
160
161namespace CLRX
162{
163
164void AsmPseudoOps::setBitness(Assembler& asmr, const char* linePtr, bool _64Bit)
165{
166    if (!checkGarbagesAtEnd(asmr, linePtr))
167        return;
168    if (asmr.formatHandler != nullptr)
169        asmr.printError(linePtr, "Bitness is already defined");
170    else if (asmr.format != BinaryFormat::AMD && asmr.format != BinaryFormat::GALLIUM)
171        asmr.printWarning(linePtr, "Bitness ignored for other formats than "
172                "AMD Catalyst and GalliumCompute");
173    else
174        asmr._64bit = (_64Bit);   
175}
176
177bool AsmPseudoOps::parseFormat(Assembler& asmr, const char* linePtr, BinaryFormat& format)
178{
179    const char* end = asmr.line + asmr.lineSize;
180    skipSpacesToEnd(linePtr, end);
181    const char* formatPlace = linePtr;
182    char formatName[10];
183    if (!getNameArg(asmr, 10, formatName, linePtr, "output format type"))
184        return false;
185   
186    toLowerString(formatName);
187    if (::strcmp(formatName, "catalyst")==0 || ::strcmp(formatName, "amd")==0)
188        format = BinaryFormat::AMD;
189    else if (::strcmp(formatName, "amdcl2")==0)
190        format = BinaryFormat::AMDCL2;
191    else if (::strcmp(formatName, "gallium")==0)
192        format = BinaryFormat::GALLIUM;
193    else if (::strcmp(formatName, "rocm")==0)
194        format = BinaryFormat::ROCM;
195    else if (::strcmp(formatName, "raw")==0)
196        format = BinaryFormat::RAWCODE;
197    else
198    {
199        asmr.printError(formatPlace, "Unknown output format type");
200        return false;
201    }
202    return true;
203}
204
205void AsmPseudoOps::setOutFormat(Assembler& asmr, const char* linePtr)
206{
207    const char* end = asmr.line + asmr.lineSize;
208    BinaryFormat format;
209    skipSpacesToEnd(linePtr, end);
210    const char* formatPlace = linePtr;
211    if (!parseFormat(asmr, linePtr, format))
212        return;
213   
214    if (checkGarbagesAtEnd(asmr, linePtr))
215    {
216        if (asmr.formatHandler!=nullptr)
217        {
218            asmr.printError(formatPlace, "Output format type is already defined");
219            return;
220        }
221        asmr.format = format;
222    }
223}
224
225void AsmPseudoOps::setGPUDevice(Assembler& asmr, const char* linePtr)
226{
227    const char* end = asmr.line + asmr.lineSize;
228    skipSpacesToEnd(linePtr, end);
229    char deviceName[64];
230    const char* deviceNamePlace = linePtr;
231    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
232        return;
233    try
234    {
235        GPUDeviceType deviceType = getGPUDeviceTypeFromName(deviceName);
236        if (checkGarbagesAtEnd(asmr, linePtr))
237            asmr.deviceType = deviceType;
238    }
239    catch(const Exception& ex)
240    { asmr.printError(deviceNamePlace, ex.what()); }
241}
242
243void AsmPseudoOps::setGPUArchitecture(Assembler& asmr, const char* linePtr)
244{
245    const char* end = asmr.line + asmr.lineSize;
246    skipSpacesToEnd(linePtr, end);
247    char deviceName[64];
248    const char* archNamePlace = linePtr;
249    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
250        return;
251    try
252    {
253        GPUArchitecture arch = getGPUArchitectureFromName(deviceName);
254        GPUDeviceType deviceType = getLowestGPUDeviceTypeFromArchitecture(arch);
255        if (checkGarbagesAtEnd(asmr, linePtr))
256            asmr.deviceType = deviceType;
257    }
258    catch(const Exception& ex)
259    { asmr.printError(archNamePlace, ex.what()); }
260}
261
262void AsmPseudoOps::goToKernel(Assembler& asmr, const char* pseudoOpPlace,
263                  const char* linePtr)
264{
265    asmr.initializeOutputFormat();
266    const char* end = asmr.line + asmr.lineSize;
267    skipSpacesToEnd(linePtr, end);
268    CString kernelName;
269    if (!getNameArg(asmr, kernelName, linePtr, "kernel name"))
270        return;
271    if (!checkGarbagesAtEnd(asmr, linePtr))
272        return;
273   
274    asmr.goToKernel(pseudoOpPlace, kernelName.c_str());
275}
276
277/// isPseudoOp - if true then name is pseudo-operation (we must convert to lower-case)
278/// if pseudo-op we just do not try to parse section flags
279void AsmPseudoOps::goToSection(Assembler& asmr, const char* pseudoOpPlace,
280                   const char* linePtr, bool isPseudoOp)
281{
282    asmr.initializeOutputFormat();
283    const char* end = asmr.line + asmr.lineSize;
284    skipSpacesToEnd(linePtr, end);
285    CString sectionName;
286    if (!getNameArg(asmr, sectionName, linePtr, "section name"))
287        return;
288    if (isPseudoOp)
289        toLowerString(sectionName);
290    bool haveFlags = false;
291    uint32_t sectFlags = 0;
292    AsmSectionType sectType = AsmSectionType::EXTRA_SECTION;
293    uint64_t sectionAlign = 0;
294    if (!isPseudoOp)
295    {
296        skipSpacesToEnd(linePtr, end);
297        if (linePtr!=end && *linePtr==',')
298        {
299            haveFlags = true;
300            linePtr++;
301        }
302    }
303    bool good = true;
304    if (haveFlags)
305    {
306        std::string flagsStr;
307        skipSpacesToEnd(linePtr, end);
308        const char* flagsStrPlace = linePtr;
309        if (asmr.parseString(flagsStr, linePtr))
310        {
311            bool flagsStrIsGood = true;
312            for (const char c: flagsStr)
313                if (c=='a')
314                    sectFlags |= ASMELFSECT_ALLOCATABLE;
315                else if (c=='x')
316                    sectFlags |= ASMELFSECT_EXECUTABLE;
317                else if (c=='w')
318                    sectFlags |= ASMELFSECT_WRITEABLE;
319                else if (flagsStrIsGood)
320                {
321                    asmr.printError(flagsStrPlace,
322                            "Only 'a', 'w', 'x' is accepted in flags string");
323                    flagsStrIsGood = good = false;
324                }
325        }
326        else
327            good = false;
328       
329        bool haveComma;
330        if (!skipComma(asmr, haveComma, linePtr))
331            return;
332        if (haveComma)
333        {   // section type
334            char typeBuf[20];
335            skipSpacesToEnd(linePtr, end);
336            const char* typePlace = linePtr;
337            if (linePtr+1<end && *linePtr=='@' && isAlpha(linePtr[1]))
338            {
339                linePtr++;
340                if (getNameArg(asmr, 20, typeBuf, linePtr, "section type"))
341                {
342                    toLowerString(typeBuf);
343                    if (::strcmp(typeBuf, "progbits")==0)
344                        sectType = AsmSectionType::EXTRA_PROGBITS;
345                    else if (::strcmp(typeBuf, "note")==0)
346                        sectType = AsmSectionType::EXTRA_NOTE;
347                    else if (::strcmp(typeBuf, "nobits")==0)
348                        sectType = AsmSectionType::EXTRA_NOBITS;
349                    else
350                    {
351                        asmr.printError(typePlace, "Unknown section type");
352                        good = false;
353                    }
354                }
355                else
356                    good = false;
357            }
358            else
359            {
360                asmr.printError(typePlace, "Section type was not preceded by '@'");
361                good = false;
362            }
363        }
364    }
365    // parse alignment
366    skipSpacesToEnd(linePtr, end);
367    if (linePtr+6<end && ::strncasecmp(linePtr, "align", 5)==0 && !isAlpha(linePtr[5]))
368    {   // if alignment
369        linePtr+=5;
370        skipSpacesToEnd(linePtr, end);
371        if (linePtr!=end && *linePtr=='=')
372        {
373            skipCharAndSpacesToEnd(linePtr, end);
374            const char* valuePtr = linePtr;
375            if (getAbsoluteValueArg(asmr, sectionAlign, linePtr, true))
376            {
377                if (sectionAlign!=0 && (1ULL<<(63-CLZ64(sectionAlign))) != sectionAlign)
378                {
379                    asmr.printError(valuePtr, "Alignment must be power of two or zero");
380                    good = false;
381                }
382            }
383            else
384                good = false;
385        }
386        else
387        {
388            asmr.printError(linePtr, "Expected '=' after 'align'");
389            good = false;
390        }
391    }
392   
393    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
394        return;
395   
396    if (!haveFlags)
397        asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectionAlign);
398    else
399        asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectType, sectFlags,
400                 sectionAlign);
401}
402
403void AsmPseudoOps::goToMain(Assembler& asmr, const char* pseudoOpPlace,
404                   const char* linePtr)
405{
406    asmr.initializeOutputFormat();
407    const char* end = asmr.line + asmr.lineSize;
408    skipSpacesToEnd(linePtr, end);
409    if (!checkGarbagesAtEnd(asmr, linePtr))
410        return;
411   
412    asmr.goToMain(pseudoOpPlace);
413}
414
415void AsmPseudoOps::includeFile(Assembler& asmr, const char* pseudoOpPlace,
416                   const char* linePtr)
417{
418    const char* end = asmr.line + asmr.lineSize;
419    skipSpacesToEnd(linePtr, end);
420    std::string filename, sysfilename;
421    const char* namePlace = linePtr;
422    if (asmr.parseString(filename, linePtr))
423    {
424        if (!checkGarbagesAtEnd(asmr, linePtr))
425            return;
426        sysfilename = filename;
427        bool failedOpen = false;
428        filesystemPath(sysfilename);
429        try
430        {
431            asmr.includeFile(pseudoOpPlace, sysfilename);
432            return;
433        }
434        catch(const Exception& ex)
435        { failedOpen = true; }
436       
437        for (const CString& incDir: asmr.includeDirs)
438        {
439            failedOpen = false;
440            std::string incDirPath(incDir.c_str());
441            filesystemPath(incDirPath);
442            try
443            {
444                asmr.includeFile(pseudoOpPlace, joinPaths(
445                            std::string(incDirPath.c_str()), sysfilename));
446                break;
447            }
448            catch(const Exception& ex)
449            { failedOpen = true; }
450        }
451        if (failedOpen)
452            asmr.printError(namePlace, (std::string("Include file '") + filename +
453                    "' not found or unavailable in any directory").c_str());
454    }
455}
456
457void AsmPseudoOps::includeBinFile(Assembler& asmr, const char* pseudoOpPlace,
458                          const char* linePtr)
459{
460    asmr.initializeOutputFormat();
461    const char* end = asmr.line + asmr.lineSize;
462   
463    if (!asmr.isWriteableSection())
464    {
465        asmr.printError(pseudoOpPlace,
466                        "Writing data into non-writeable section is illegal");
467        return;
468    }
469   
470    skipSpacesToEnd(linePtr, end);
471    std::string filename, sysfilename;
472    const char* namePlace = linePtr;
473    const char* offsetPlace = linePtr;
474    const char* countPlace = linePtr;
475    uint64_t offset = 0, count = INT64_MAX;
476   
477    bool good = asmr.parseString(filename, linePtr);
478    bool haveComma;
479   
480    if (!skipComma(asmr, haveComma, linePtr))
481        return;
482    if (haveComma)
483    {
484        skipSpacesToEnd(linePtr, end);
485        offsetPlace = linePtr;
486        if (getAbsoluteValueArg(asmr, offset, linePtr))
487        {
488            if (int64_t(offset) < 0)
489            {
490                asmr.printError(offsetPlace, "Offset is negative!");
491                good = false;
492            }
493        }
494        else
495            good = false;
496       
497        if (!skipComma(asmr, haveComma, linePtr))
498            return;
499        if (haveComma)
500        {
501            skipSpacesToEnd(linePtr, end);
502            countPlace = linePtr;
503            good &= getAbsoluteValueArg(asmr, count, linePtr);
504            if (int64_t(count) < 0)
505            {
506                asmr.printError(countPlace, "Count bytes is negative!");
507                good = false;
508            }
509        }
510    }
511   
512    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // failed parsing
513        return;
514   
515    if (count == 0)
516    {
517        asmr.printWarning(namePlace, "Number of bytes is zero, ignoring .incbin");
518        return;
519    }
520   
521    std::ifstream ifs;
522    sysfilename = filename;
523    filesystemPath(sysfilename);
524    ifs.open(sysfilename.c_str(), std::ios::binary);
525    if (!ifs)
526    {
527        for (const CString& incDir: asmr.includeDirs)
528        {
529            std::string incDirPath(incDir.c_str());
530            filesystemPath(incDirPath);
531            ifs.open(joinPaths(incDirPath.c_str(), sysfilename).c_str(), std::ios::binary);
532            if (ifs)
533                break;
534        }
535    }
536    if (!ifs)
537    {
538        asmr.printError(namePlace, (std::string("Binary file '") + filename +
539                    "' not found or unavailable in any directory").c_str());
540        return;
541    }
542    // exception for checking file seeking
543    bool seekingIsWorking = true;
544    ifs.exceptions(std::ios::badbit | std::ios::failbit); // exceptions
545    try
546    { ifs.seekg(0, std::ios::end); /* to end of file */ }
547    catch(const std::exception& ex)
548    {   /* oh, no! this is not regular file */
549        seekingIsWorking = false;
550        ifs.clear();
551    }
552    ifs.exceptions(std::ios::badbit);  // exceptions for reading
553    if (seekingIsWorking)
554    {   /* for regular files */
555        const uint64_t size = ifs.tellg();
556        if (size < offset)
557            return; // do nothing
558        ifs.seekg(offset, std::ios::beg);
559        const uint64_t toRead = std::min(size-offset, count);
560        char* output = reinterpret_cast<char*>(asmr.reserveData(toRead));
561        ifs.read(output, toRead);
562        if (ifs.gcount() != std::streamsize(toRead))
563        {
564            asmr.printError(namePlace, "Can't read whole needed file content");
565            return;
566        }
567    }
568    else
569    {   /* for sequential files, likes fifo */
570        char tempBuf[256];
571        /// first we skipping bytes given in offset
572        for (uint64_t pos = 0; pos < offset; )
573        {
574            const size_t toRead = std::min(offset-pos, uint64_t(256));
575            ifs.read(tempBuf, toRead);
576            const uint64_t readed = ifs.gcount();
577            pos += readed;
578            if (readed < toRead)
579                break;
580        }
581        // read data from binary file
582        for (uint64_t bytes = 0; bytes < count; )
583        {
584            const size_t toRead = std::min(uint64_t(256), count-bytes);
585            ifs.read(tempBuf, toRead);
586            const uint64_t readed = ifs.gcount();
587            asmr.putData(readed, (cxbyte*)tempBuf);
588            bytes += readed;
589            if (readed < toRead)
590                break;
591        }
592    }
593}
594
595void AsmPseudoOps::doFail(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
596{
597    const char* end = asmr.line + asmr.lineSize;
598    skipSpacesToEnd(linePtr, end);
599    uint64_t value = 0;
600    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
601        return;
602    if (!checkGarbagesAtEnd(asmr, linePtr))
603        return;
604   
605    char buf[50];
606    ::memcpy(buf, ".fail ", 6);
607    const size_t pos = 6+itocstrCStyle(int64_t(value), buf+6, 50-6);
608    ::memcpy(buf+pos, " encountered", 13);
609    if (int64_t(value) >= 500)
610        asmr.printWarning(pseudoOpPlace, buf);
611    else
612        asmr.printError(pseudoOpPlace, buf);
613}
614
615void AsmPseudoOps::doError(Assembler& asmr, const char* pseudoOpPlace,
616                      const char* linePtr)
617{
618    const char* end = asmr.line + asmr.lineSize;
619    skipSpacesToEnd(linePtr, end);
620    if (linePtr != end)
621    {
622        std::string outStr;
623        if (!asmr.parseString(outStr, linePtr))
624            return; // error
625        if (!checkGarbagesAtEnd(asmr, linePtr))
626            return;
627        asmr.printError(pseudoOpPlace, outStr.c_str());
628    }
629    else
630        asmr.printError(pseudoOpPlace, ".error encountered");
631}
632
633void AsmPseudoOps::doWarning(Assembler& asmr, const char* pseudoOpPlace,
634                        const char* linePtr)
635{
636    const char* end = asmr.line + asmr.lineSize;
637    skipSpacesToEnd(linePtr, end);
638    if (linePtr != end)
639    {
640        std::string outStr;
641        if (!asmr.parseString(outStr, linePtr))
642            return; // error
643        if (!checkGarbagesAtEnd(asmr, linePtr))
644            return;
645        asmr.printWarning(pseudoOpPlace, outStr.c_str());
646    }
647    else
648        asmr.printWarning(pseudoOpPlace, ".warning encountered");
649}
650
651template<typename T>
652void AsmPseudoOps::putIntegers(Assembler& asmr, const char* pseudoOpPlace,
653                   const char* linePtr)
654{
655    const char* end = asmr.line + asmr.lineSize;
656    asmr.initializeOutputFormat();
657    if (!asmr.isWriteableSection())
658    {
659        asmr.printError(pseudoOpPlace,
660                "Writing data into non-writeable section is illegal");
661        return;
662    }
663    skipSpacesToEnd(linePtr, end);
664    if (linePtr == end)
665        return;
666    do {
667        const char* exprPlace = linePtr;
668        std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr));
669        if (expr)
670        {
671            if (expr->isEmpty()) // empty expression print warning
672                asmr.printWarning(linePtr, "No expression, zero has been put");
673           
674            if (expr->getSymOccursNum()==0)
675            {   // put directly to section
676                uint64_t value;
677                cxuint sectionId;
678                if (expr->evaluate(asmr, value, sectionId))
679                {
680                    if (sectionId == ASMSECT_ABS)
681                    {
682                        if (sizeof(T) < 8)
683                            asmr.printWarningForRange(sizeof(T)<<3, value,
684                                         asmr.getSourcePos(exprPlace));
685                        T out;
686                        SLEV(out, value);
687                        asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&out));
688                    }
689                    else
690                        asmr.printError(exprPlace, "Expression must be absolute!");
691                }
692            }
693            else // expression, we set target of expression (just data)
694            {   /// will be resolved later
695                expr->setTarget(AsmExprTarget::dataTarget<T>(
696                                asmr.currentSection, asmr.currentOutPos));
697                expr.release();
698                asmr.reserveData(sizeof(T));
699            }
700        }
701    } while(skipCommaForMultipleArgs(asmr, linePtr));
702    checkGarbagesAtEnd(asmr, linePtr);
703}
704
705template<typename T> inline
706T asmcstrtofCStyleLEV(const char* str, const char* inend, const char*& outend);
707
708template<> inline
709uint16_t asmcstrtofCStyleLEV<uint16_t>(const char* str, const char* inend,
710                   const char*& outend)
711{ return LEV(cstrtohCStyle(str, inend, outend)); }
712
713template<> inline
714uint32_t asmcstrtofCStyleLEV<uint32_t>(const char* str, const char* inend,
715                   const char*& outend)
716{
717    union {
718        float f;
719        uint32_t u;
720    } value;
721    value.f = cstrtovCStyle<float>(str, inend, outend);
722    return LEV(value.u);
723}
724
725template<> inline
726uint64_t asmcstrtofCStyleLEV<uint64_t>(const char* str, const char* inend,
727                   const char*& outend)
728{
729    union {
730        double f;
731        uint64_t u;
732    } value;
733    value.f = cstrtovCStyle<double>(str, inend, outend);
734    return LEV(value.u);
735}
736
737template<typename UIntType>
738void AsmPseudoOps::putFloats(Assembler& asmr, const char* pseudoOpPlace,
739                     const char* linePtr)
740{
741    const char* end = asmr.line + asmr.lineSize;
742    asmr.initializeOutputFormat();
743    if (!asmr.isWriteableSection())
744    {
745        asmr.printError(pseudoOpPlace,
746                    "Writing data into non-writeable section is illegal");
747        return;
748    }
749    skipSpacesToEnd(linePtr, end);
750    if (linePtr == end)
751        return;
752    do {
753        UIntType out = 0;
754        const char* literalPlace = linePtr;
755        if (linePtr != end && *linePtr != ',')
756        {
757            try
758            { out = asmcstrtofCStyleLEV<UIntType>(linePtr, end, linePtr); }
759            catch(const ParseException& ex)
760            { asmr.printError(literalPlace, ex.what()); }
761        }
762        else // warning
763            asmr.printWarning(literalPlace,
764                      "No floating point literal, zero has been put");
765        asmr.putData(sizeof(UIntType), reinterpret_cast<const cxbyte*>(&out));
766       
767    } while (skipCommaForMultipleArgs(asmr, linePtr));
768    checkGarbagesAtEnd(asmr, linePtr);
769}
770
771void AsmPseudoOps::putUInt128s(Assembler& asmr, const char* pseudoOpPlace,
772                   const char* linePtr)
773{
774    const char* end = asmr.line + asmr.lineSize;
775    asmr.initializeOutputFormat();
776    if (!asmr.isWriteableSection())
777    {
778        asmr.printError(pseudoOpPlace,
779                    "Writing data into non-writeable section is illegal");
780        return;
781    }
782    skipSpacesToEnd(linePtr, end);
783    if (linePtr == end)
784        return;
785    do {
786        UInt128 value = { 0, 0 };
787        if (linePtr != end && *linePtr != ',')
788        {
789            const char* literalPlace = linePtr;
790            bool negative = false;
791            if (*linePtr == '+')
792                linePtr++;
793            else if (*linePtr == '-')
794            {
795                negative = true;
796                linePtr++;
797            }
798            try
799            { value = cstrtou128CStyle(linePtr, end, linePtr); }
800            catch(const ParseException& ex)
801            { asmr.printError(literalPlace, ex.what()); }
802            if (negative)
803            {   // negate value
804                value.hi = ~value.hi + (value.lo==0);
805                value.lo = -value.lo;
806            }
807        }
808        else // warning
809            asmr.printWarning(linePtr, "No 128-bit literal, zero has been put");
810        UInt128 out;
811        SLEV(out.lo, value.lo);
812        SLEV(out.hi, value.hi);
813        asmr.putData(16, reinterpret_cast<const cxbyte*>(&out));
814    } while (skipCommaForMultipleArgs(asmr, linePtr));
815    checkGarbagesAtEnd(asmr, linePtr);
816}
817
818void AsmPseudoOps::putStrings(Assembler& asmr, const char* pseudoOpPlace,
819                      const char* linePtr, bool addZero)
820{
821    const char* end = asmr.line + asmr.lineSize;
822    asmr.initializeOutputFormat();
823    if (!asmr.isWriteableSection())
824    {
825        asmr.printError(pseudoOpPlace,
826                    "Writing data into non-writeable section is illegal");
827        return;
828    }
829    skipSpacesToEnd(linePtr, end);
830    if (linePtr == end)
831        return;
832    do {
833        std::string outStr;
834        if (*linePtr != ',')
835        {
836            if (asmr.parseString(outStr, linePtr))
837                asmr.putData(outStr.size()+(addZero), (const cxbyte*)outStr.c_str());
838        }
839    } while (skipCommaForMultipleArgs(asmr, linePtr));
840    checkGarbagesAtEnd(asmr, linePtr);
841}
842
843template<typename T>
844void AsmPseudoOps::putStringsToInts(Assembler& asmr, const char* pseudoOpPlace,
845                    const char* linePtr)
846{
847    const char* end = asmr.line + asmr.lineSize;
848    if (!asmr.isWriteableSection())
849    {
850        asmr.printError(pseudoOpPlace,
851                    "Writing data into non-writeable section is illegal");
852        return;
853    }
854    asmr.initializeOutputFormat();
855    skipSpacesToEnd(linePtr, end);
856    if (linePtr == end)
857        return;
858    do {
859        std::string outStr;
860        if (*linePtr != ',')
861        {
862            if (asmr.parseString(outStr, linePtr))
863            {
864                const size_t strSize = outStr.size()+1;
865                T* outData = reinterpret_cast<T*>(
866                        asmr.reserveData(sizeof(T)*(strSize)));
867                /// put as integer including nul-terminated string
868                for (size_t i = 0; i < strSize; i++)
869                    SULEV(outData[i], T(outStr[i])&T(0xff));
870            }
871        }
872       
873    } while (skipCommaForMultipleArgs(asmr, linePtr));
874    checkGarbagesAtEnd(asmr, linePtr);
875}
876
877void AsmPseudoOps::setSymbol(Assembler& asmr, const char* linePtr, bool reassign,
878                 bool baseExpr)
879{
880    const char* end = asmr.line + asmr.lineSize;
881    skipSpacesToEnd(linePtr, end);
882    const char* strAtSymName = linePtr;
883    CString symName = extractSymName(linePtr, end, false);
884    bool good = true;
885    if (symName.empty())
886    {
887        asmr.printError(linePtr, "Expected symbol");
888        good = false;
889    }
890    if (!skipRequiredComma(asmr, linePtr))
891        return;
892    if (good) // is not so good
893        asmr.assignSymbol(symName, strAtSymName, linePtr, reassign, baseExpr);
894}
895
896void AsmPseudoOps::setSymbolBind(Assembler& asmr, const char* linePtr, cxbyte bind)
897{
898    const char* end = asmr.line + asmr.lineSize;
899    skipSpacesToEnd(linePtr, end);
900    do {
901        const char* symNamePlace = linePtr;
902        AsmSymbolEntry* symEntry;
903        Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
904        bool good = (state != Assembler::ParseState::FAILED);
905        if (symEntry == nullptr)
906        {
907            asmr.printError(symNamePlace, "Expected symbol name");
908            good = false;
909        }
910        else if (symEntry->second.regRange)
911        {
912            asmr.printError(symNamePlace, "Symbol must not be register symbol");
913            good = false;
914        }
915        else if (symEntry->second.base)
916        {
917            asmr.printError(symNamePlace,
918                "Symbol must not be set by .eqv pseudo-op or must be constant");
919            good = false;
920        }
921       
922        if (good)
923        {
924            if (symEntry->first != ".")
925                symEntry->second.info = ELF32_ST_INFO(bind,
926                      ELF32_ST_TYPE(symEntry->second.info));
927            else
928                asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
929        }
930       
931    } while(skipCommaForMultipleArgs(asmr, linePtr));
932    checkGarbagesAtEnd(asmr, linePtr);
933}
934
935void AsmPseudoOps::setSymbolSize(Assembler& asmr, const char* linePtr)
936{
937    const char* end = asmr.line + asmr.lineSize;
938    skipSpacesToEnd(linePtr, end);
939    const char* symNamePlace = linePtr;
940    AsmSymbolEntry* symEntry;
941    Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
942    bool good = (state != Assembler::ParseState::FAILED);
943    if (symEntry == nullptr)
944    {
945        asmr.printError(symNamePlace, "Expected symbol name");
946        good = false;
947    }
948    if (!skipRequiredComma(asmr, linePtr))
949        return;
950    // parse size
951    uint64_t size;
952    good &= getAbsoluteValueArg(asmr, size, linePtr, true);
953    bool ignore = false;
954    if (symEntry != nullptr)
955    {
956        if (symEntry->second.base)
957        {
958            asmr.printError(symNamePlace,
959                    "Symbol must not be set by .eqv pseudo-op or must be constant");
960            good = false;
961        }
962        else if (symEntry->second.regRange)
963        {
964            asmr.printError(symNamePlace, "Symbol must not be register symbol");
965            good = false;
966        }
967        else if (symEntry->first == ".")
968        {
969            asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
970            ignore = true;
971        }
972    }
973   
974    if (good && checkGarbagesAtEnd(asmr, linePtr))
975        if (!ignore) // ignore if '.'
976            symEntry->second.size = size;
977}
978
979void AsmPseudoOps::ignoreExtern(Assembler& asmr, const char* linePtr)
980{
981    const char* end = asmr.line + asmr.lineSize;
982    skipSpacesToEnd(linePtr, end);
983    if (linePtr == end)
984        return;
985    do {
986        asmr.skipSymbol(linePtr);
987    } while (skipCommaForMultipleArgs(asmr, linePtr));
988    checkGarbagesAtEnd(asmr, linePtr);
989}
990
991void AsmPseudoOps::doFill(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
992          bool _64bit)
993{
994    asmr.initializeOutputFormat();
995    const char* end = asmr.line + asmr.lineSize;
996   
997    if (!asmr.isWriteableSection())
998    {
999        asmr.printError(pseudoOpPlace,
1000                    "Writing data into non-writeable section is illegal");
1001        return;
1002    }
1003   
1004    skipSpacesToEnd(linePtr, end);
1005    uint64_t repeat = 0, size = 1, value = 0;
1006   
1007    const char* reptStr = linePtr;
1008    bool good = getAbsoluteValueArg(asmr, repeat, linePtr, true);
1009   
1010    if (int64_t(repeat) < 0)
1011        asmr.printWarning(reptStr, "Negative repeat has no effect");
1012   
1013    bool haveComma = false;
1014    if (!skipComma(asmr, haveComma, linePtr))
1015        return;
1016    const char* sizePlace = linePtr;
1017    const char* fillValuePlace = linePtr;
1018    if (haveComma)
1019    {
1020        skipSpacesToEnd(linePtr, end);
1021        sizePlace = linePtr; //
1022        if (getAbsoluteValueArg(asmr, size, linePtr))
1023        {
1024            if (int64_t(size) < 0)
1025                asmr.printWarning(sizePlace, "Negative size has no effect");
1026        }
1027        else
1028            good = false;
1029       
1030        if (!skipComma(asmr, haveComma, linePtr))
1031            return;
1032        if (haveComma)
1033        {
1034            skipSpacesToEnd(linePtr, end);
1035            fillValuePlace = linePtr;
1036            good &= getAbsoluteValueArg(asmr, value, linePtr);
1037        }
1038    }
1039    if (int64_t(size) > 0 && int64_t(repeat) > 0 && SSIZE_MAX/size < repeat)
1040    {
1041        asmr.printError(pseudoOpPlace, "Product of repeat and size is too big");
1042        good = false;
1043    }
1044   
1045    cxuint truncBits = std::min(uint64_t(8), size)<<3;
1046    /* honors old behaviour from original GNU as (just cut to 32-bit values)
1047     * do not that for .fillq (_64bit=true) */
1048    if (!_64bit)
1049        truncBits = std::min(cxuint(32), truncBits);
1050    if (truncBits != 0 && truncBits < 64) // if print
1051        asmr.printWarningForRange(truncBits, value, asmr.getSourcePos(fillValuePlace));
1052   
1053    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // if parsing failed
1054        return;
1055   
1056    if (int64_t(repeat) <= 0 || int64_t(size) <= 0)
1057        return;
1058   
1059    if (!_64bit)
1060        value &= 0xffffffffUL;
1061   
1062    /* do fill */
1063    cxbyte* content = asmr.reserveData(size*repeat);
1064    const size_t valueSize = std::min(uint64_t(8), size);
1065    uint64_t outValue;
1066    SLEV(outValue, value);
1067    // main filling route (slow)
1068    for (uint64_t r = 0; r < repeat; r++)
1069    {
1070        ::memcpy(content, &outValue, valueSize);
1071        ::memset(content+valueSize, 0, size-valueSize);
1072        content += size;
1073    }
1074}
1075
1076void AsmPseudoOps::doSkip(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1077{
1078    asmr.initializeOutputFormat();
1079    const char* end = asmr.line + asmr.lineSize;
1080   
1081    if (!asmr.isAddressableSection())
1082    {
1083        asmr.printError(pseudoOpPlace,
1084                    "Change output counter inside non-addressable section is illegal");
1085        return;
1086    }
1087   
1088    skipSpacesToEnd(linePtr, end);
1089    uint64_t size = 1, value = 0;
1090   
1091    const char* sizePlace = linePtr;
1092    bool good = getAbsoluteValueArg(asmr, size, linePtr);
1093    if (int64_t(size) < 0)
1094        asmr.printWarning(sizePlace, "Negative size has no effect");
1095   
1096    bool haveComma = false;
1097    if (!skipComma(asmr, haveComma, linePtr))
1098        return;
1099    const char* fillValuePlace = linePtr;
1100    if (haveComma)
1101    {
1102        skipSpacesToEnd(linePtr, end);
1103        fillValuePlace = linePtr;
1104        if (getAbsoluteValueArg(asmr, value, linePtr))
1105            asmr.printWarningForRange(8, value, asmr.getSourcePos(fillValuePlace));
1106        else
1107            good = false;
1108    }
1109    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1110        return;
1111   
1112    if (int64_t(size) < 0)
1113        return;
1114   
1115    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1116        asmr.printWarning(fillValuePlace, "Fill value is ignored inside absolute section");
1117    asmr.reserveData(size, value&0xff);
1118}
1119
1120void AsmPseudoOps::doAlign(Assembler& asmr, const char* pseudoOpPlace,
1121                           const char* linePtr, bool powerOf2)
1122{
1123    asmr.initializeOutputFormat();
1124    const char* end = asmr.line + asmr.lineSize;
1125   
1126    if (!asmr.isAddressableSection())
1127    {
1128        asmr.printError(pseudoOpPlace,
1129                    "Change output counter inside non-addressable section is illegal");
1130        return;
1131    }
1132   
1133    skipSpacesToEnd(linePtr, end);
1134    uint64_t alignment, value = 0, maxAlign = 0;
1135    const char* alignPlace = linePtr;
1136    bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
1137   
1138    if (good)
1139    {
1140        if (powerOf2)
1141        {
1142            if (alignment > 63)
1143            {
1144                asmr.printError(alignPlace, "Power of 2 of alignment is greater than 63");
1145                good = false;
1146            }
1147            else
1148                alignment = (1ULL<<alignment);
1149        }
1150        else if (alignment == 0 || (1ULL<<(63-CLZ64(alignment))) != alignment)
1151        {
1152            asmr.printError(alignPlace, "Alignment is not power of 2");
1153            good = false;
1154        }
1155    }
1156   
1157    bool haveValue = false;
1158    if (!skipComma(asmr, haveValue, linePtr))
1159        return;
1160    const char* valuePlace = linePtr;
1161    if (haveValue)
1162    {
1163        skipSpacesToEnd(linePtr, end);
1164        valuePlace = linePtr;
1165        if (getAbsoluteValueArg(asmr, value, linePtr))
1166            asmr.printWarningForRange(8, value, asmr.getSourcePos(valuePlace));
1167        else
1168            good = false;
1169       
1170        bool haveComma = false;
1171        if (!skipComma(asmr, haveComma, linePtr))
1172            return;
1173        if (haveComma)
1174        {
1175            skipSpacesToEnd(linePtr, end);
1176            good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
1177        }
1178    }
1179    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) //if parsing failed
1180        return;
1181   
1182    uint64_t outPos = asmr.currentOutPos;
1183    const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
1184            alignment - (outPos&(alignment-1)) : 0;
1185    if (maxAlign!=0 && bytesToFill > maxAlign)
1186        return; // do not make alignment
1187   
1188    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1189        asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
1190   
1191    if (haveValue || asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
1192        asmr.reserveData(bytesToFill, value&0xff);
1193    else /* only if no value and is code section */
1194    {
1195        cxbyte* output = asmr.reserveData(bytesToFill, 0);
1196        asmr.isaAssembler->fillAlignment(bytesToFill, output);
1197    }
1198}
1199
1200template<typename Word>
1201void AsmPseudoOps::doAlignWord(Assembler& asmr, const char* pseudoOpPlace,
1202                       const char* linePtr)
1203{
1204    asmr.initializeOutputFormat();
1205    const char* end = asmr.line + asmr.lineSize;
1206   
1207    if (!asmr.isAddressableSection())
1208    {
1209        asmr.printError(pseudoOpPlace,
1210                    "Change output counter inside non-addressable section is illegal");
1211        return;
1212    }
1213   
1214    skipSpacesToEnd(linePtr, end);
1215    uint64_t alignment, value = 0, maxAlign = 0;
1216    const char* alignPlace = linePtr;
1217    bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
1218    if (good && alignment != 0 && (1ULL<<(63-CLZ64(alignment))) != alignment)
1219    {
1220        asmr.printError(alignPlace, "Alignment is not power of 2");
1221        good = false;
1222    }
1223   
1224    bool haveValue = false;
1225    if (!skipComma(asmr, haveValue, linePtr))
1226        return;
1227    const char* valuePlace = linePtr;
1228    if (haveValue)
1229    {
1230        skipSpacesToEnd(linePtr, end);
1231        valuePlace = linePtr;
1232        if (getAbsoluteValueArg(asmr, value, linePtr))
1233            asmr.printWarningForRange(sizeof(Word)<<3, value,
1234                          asmr.getSourcePos(valuePlace));
1235        else
1236            good = false;
1237       
1238        bool haveComma = false;
1239        if (!skipComma(asmr, haveComma, linePtr))
1240            return;
1241        if (haveComma)
1242        {
1243            skipSpacesToEnd(linePtr, end);
1244            good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
1245        }
1246    }
1247    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1248        return;
1249   
1250    if (alignment == 0)
1251        return; // do nothing
1252   
1253    uint64_t outPos = asmr.currentOutPos;
1254    if (outPos&(sizeof(Word)-1))
1255    {
1256        asmr.printError(pseudoOpPlace, "Offset is not aligned to word");
1257        return;
1258    }
1259   
1260    const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
1261            alignment - (outPos&(alignment-1)) : 0;
1262   
1263    if (maxAlign!=0 && bytesToFill > maxAlign)
1264        return; // do not make alignment
1265   
1266    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1267    {
1268        asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
1269        asmr.reserveData(bytesToFill);
1270        return;
1271    }
1272    cxbyte* content = asmr.reserveData(bytesToFill);
1273    if (haveValue)
1274    {
1275        Word word;
1276        SLEV(word, value);
1277        std::fill(reinterpret_cast<Word*>(content),
1278                  reinterpret_cast<Word*>(content + bytesToFill), word);
1279    }
1280    else if (asmr.sections[asmr.currentSection].type == AsmSectionType::CODE)
1281        asmr.isaAssembler->fillAlignment(bytesToFill, content);
1282}
1283
1284void AsmPseudoOps::doOrganize(Assembler& asmr, const char* linePtr)
1285{
1286    asmr.initializeOutputFormat();
1287    const char* end = asmr.line + asmr.lineSize;
1288    skipSpacesToEnd(linePtr, end);
1289    uint64_t value;
1290    cxuint sectionId = ASMSECT_ABS;
1291    const char* valuePlace = linePtr;
1292    bool good = getAnyValueArg(asmr, value, sectionId, linePtr);
1293   
1294    uint64_t fillValue = 0;
1295    bool haveComma;
1296    if (!skipComma(asmr, haveComma, linePtr))
1297        return;
1298    const char* fillValuePlace = linePtr;
1299    if (haveComma) // optional fill argument
1300    {
1301        skipSpacesToEnd(linePtr, end);
1302        fillValuePlace = linePtr;
1303        good = getAbsoluteValueArg(asmr, fillValue, linePtr, true);
1304    }
1305    asmr.printWarningForRange(8, fillValue, asmr.getSourcePos(fillValuePlace));
1306   
1307    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1308        return;
1309   
1310    asmr.assignOutputCounter(valuePlace, value, sectionId, fillValue);
1311}
1312
1313void AsmPseudoOps::doPrint(Assembler& asmr, const char* linePtr)
1314{
1315    std::string outStr;
1316    if (!asmr.parseString(outStr, linePtr))
1317        return;
1318    if (!AsmPseudoOps::checkGarbagesAtEnd(asmr, linePtr))
1319        return;
1320    asmr.printStream.write(outStr.c_str(), outStr.size());
1321    asmr.printStream.put('\n');
1322}
1323
1324/// perform .if for integer comparisons '.iflt', '.ifle', '.ifne'
1325void AsmPseudoOps::doIfInt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1326               IfIntComp compType, bool elseIfClause)
1327{
1328    const char* end = asmr.line + asmr.lineSize;
1329    skipSpacesToEnd(linePtr, end);
1330    uint64_t value;
1331    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
1332    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1333        return;
1334   
1335    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1336            AsmClauseType::IF;
1337    bool satisfied;
1338    switch(compType)
1339    {
1340        case IfIntComp::EQUAL:
1341            satisfied = (value == 0);
1342            break;
1343        case IfIntComp::NOT_EQUAL:
1344            satisfied = (value != 0);
1345            break;
1346        case IfIntComp::LESS:
1347            satisfied = (int64_t(value) < 0);
1348            break;
1349        case IfIntComp::LESS_EQUAL:
1350            satisfied = (int64_t(value) <= 0);
1351            break;
1352        case IfIntComp::GREATER:
1353            satisfied = (int64_t(value) > 0);
1354            break;
1355        case IfIntComp::GREATER_EQUAL:
1356            satisfied = (int64_t(value) >= 0);
1357            break;
1358        default:
1359            satisfied = false;
1360            break;
1361    }
1362    bool included;
1363    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1364    {   //
1365        if (!included) // skip clauses (do not perform statements)
1366            asmr.skipClauses();
1367    }
1368}
1369
1370void AsmPseudoOps::doIfDef(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1371               bool negation, bool elseIfClause)
1372{
1373    const char* end = asmr.line + asmr.lineSize;
1374    skipSpacesToEnd(linePtr, end);
1375    const char* symNamePlace = linePtr;
1376    AsmSymbolEntry* entry;
1377    bool good = true;
1378    Assembler::ParseState state = asmr.parseSymbol(linePtr, entry, false, true);
1379    if (state == Assembler::ParseState::FAILED)
1380        return;
1381    if (state == Assembler::ParseState::MISSING)
1382    {
1383        asmr.printError(symNamePlace, "Expected symbol");
1384        good = false;
1385    }
1386    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1387        return;
1388   
1389    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1390            AsmClauseType::IF;
1391    bool included;
1392    const bool symDefined = (entry!=nullptr && (entry->second.hasValue ||
1393                entry->second.expression!=nullptr));
1394    bool satisfied = (!negation) ?  symDefined : !symDefined;
1395    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1396    {   //
1397        if (!included) // skip clauses (do not perform statements)
1398            asmr.skipClauses();
1399    }
1400}
1401
1402void AsmPseudoOps::doIfBlank(Assembler& asmr, const char* pseudoOpPlace,
1403             const char* linePtr, bool negation, bool elseIfClause)
1404{
1405    const char* end = asmr.line + asmr.lineSize;
1406    skipSpacesToEnd(linePtr, end);
1407   
1408    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1409            AsmClauseType::IF;
1410    bool included;
1411    bool satisfied = (!negation) ? linePtr==end : linePtr!=end;
1412    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1413    {   //
1414        if (!included) // skip clauses (do not perform statements)
1415            asmr.skipClauses();
1416    }
1417}
1418
1419static std::string getStringToCompare(const char* strStart, const char* strEnd)
1420{
1421    std::string firstStr;
1422    bool blank = true;
1423    bool singleQuote = false;
1424    bool dblQuote = false;
1425    cxbyte prevTok = 0;
1426    for (const char* s = strStart; s != strEnd; ++s)
1427        if (isSpace(*s))
1428        {
1429            if (!blank || dblQuote || singleQuote)
1430                firstStr.push_back(*s);
1431            blank = true;
1432        }
1433        else
1434        {
1435            blank = false;
1436            if (*s == '"' && !singleQuote)
1437                dblQuote = !dblQuote;
1438            else if (*s == '\'' && !dblQuote)
1439                singleQuote = !singleQuote;
1440           
1441            /* original GNU as tokenize line before processing, this code 'emulates'
1442             * this operation */
1443            cxbyte thisTok = (cxbyte(*s) >= 0x20 && cxbyte(*s) <= 0x80) ?
1444                    tokenCharTable[*s-0x20] : 0;
1445            if (!singleQuote && !dblQuote && !firstStr.empty() &&
1446                isSpace(firstStr.back()) &&
1447                ((prevTok != thisTok) || ((prevTok == thisTok) && (prevTok & 0x80)==0)))
1448                firstStr.pop_back();// delete space between different tokens
1449           
1450            firstStr.push_back(*s);
1451            prevTok = thisTok;
1452        }
1453    if (!firstStr.empty() && isSpace(firstStr.back()))
1454        firstStr.pop_back(); // remove last space
1455    return firstStr;
1456}
1457
1458void AsmPseudoOps::doIfCmpStr(Assembler& asmr, const char* pseudoOpPlace,
1459               const char* linePtr, bool negation, bool elseIfClause)
1460{
1461    const char* end = asmr.line + asmr.lineSize;
1462    skipSpacesToEnd(linePtr, end);
1463    const char* firstStrStart = linePtr;
1464    bool good = true;
1465    while (linePtr != end && *linePtr != ',') linePtr++;
1466    if (linePtr == end)
1467    {
1468        asmr.printError(linePtr, "Missing second string");
1469        return;
1470    }
1471    const char* firstStrEnd = linePtr;
1472    if (good) linePtr++; // comma
1473    else return;
1474   
1475    std::string firstStr = getStringToCompare(firstStrStart, firstStrEnd);
1476    std::string secondStr = getStringToCompare(linePtr, end);
1477   
1478    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1479            AsmClauseType::IF;
1480    bool included;
1481    bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
1482    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1483    {   //
1484        if (!included) // skip clauses (do not perform statements)
1485            asmr.skipClauses();
1486    }
1487}
1488
1489void AsmPseudoOps::doIfStrEqual(Assembler& asmr, const char* pseudoOpPlace,
1490                const char* linePtr, bool negation, bool elseIfClause)
1491{
1492    const char* end = asmr.line + asmr.lineSize;
1493    skipSpacesToEnd(linePtr, end);
1494    std::string firstStr, secondStr;
1495    bool good = asmr.parseString(firstStr, linePtr);
1496    if (!skipRequiredComma(asmr, linePtr))
1497        return;
1498    skipSpacesToEnd(linePtr, end);
1499    good &= asmr.parseString(secondStr, linePtr);
1500    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1501        return;
1502   
1503    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1504            AsmClauseType::IF;
1505    bool included;
1506    bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
1507    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1508    {   //
1509        if (!included) // skip clauses (do not perform statements)
1510            asmr.skipClauses();
1511    }
1512}
1513
1514void AsmPseudoOps::doIf64Bit(Assembler& asmr, const char* pseudoOpPlace,
1515                const char* linePtr, bool negation, bool elseIfClause)
1516{
1517    if (!checkGarbagesAtEnd(asmr, linePtr))
1518        return;
1519   
1520    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1521            AsmClauseType::IF;
1522    bool included;
1523    bool satisfied = (!negation) ? asmr._64bit : !asmr._64bit;
1524    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1525    {   //
1526        if (!included) // skip clauses (do not perform statements)
1527            asmr.skipClauses();
1528    }
1529}
1530
1531void AsmPseudoOps::doIfArch(Assembler& asmr, const char* pseudoOpPlace,
1532            const char* linePtr, bool negation, bool elseIfClause)
1533{
1534    const char* end = asmr.line + asmr.lineSize;
1535    skipSpacesToEnd(linePtr, end);
1536    char deviceName[64];
1537    const char* archNamePlace = linePtr;
1538    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
1539        return;
1540    GPUArchitecture arch;
1541    try
1542    {
1543        arch = getGPUArchitectureFromName(deviceName);
1544        if (!checkGarbagesAtEnd(asmr, linePtr))
1545            return;
1546    }
1547    catch(const Exception& ex)
1548    { 
1549        asmr.printError(archNamePlace, ex.what());
1550        return;
1551    }
1552   
1553    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1554            AsmClauseType::IF;
1555    bool included;
1556    GPUArchitecture curArch = getGPUArchitectureFromDeviceType(asmr.getDeviceType());
1557    bool satisfied = (!negation) ? arch==curArch : arch!=curArch;
1558    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1559    {   //
1560        if (!included) // skip clauses (do not perform statements)
1561            asmr.skipClauses();
1562    }
1563}
1564
1565void AsmPseudoOps::doIfGpu(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1566            bool negation, bool elseIfClause)
1567{
1568    const char* end = asmr.line + asmr.lineSize;
1569    skipSpacesToEnd(linePtr, end);
1570    char deviceName[64];
1571    const char* deviceNamePlace = linePtr;
1572    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
1573        return;
1574    GPUDeviceType deviceType;
1575    try
1576    {
1577        deviceType = getGPUDeviceTypeFromName(deviceName);
1578        if (!checkGarbagesAtEnd(asmr, linePtr))
1579            return;
1580    }
1581    catch(const Exception& ex)
1582    {
1583        asmr.printError(deviceNamePlace, ex.what());
1584        return;
1585    }
1586   
1587    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1588            AsmClauseType::IF;
1589    bool included;
1590    bool satisfied = (!negation) ? deviceType==asmr.deviceType :
1591                deviceType!=asmr.deviceType;
1592    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1593    {   //
1594        if (!included) // skip clauses (do not perform statements)
1595            asmr.skipClauses();
1596    }
1597}
1598
1599void AsmPseudoOps::doIfFmt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1600            bool negation, bool elseIfClause)
1601{
1602    const char* end = asmr.line + asmr.lineSize;
1603    skipSpacesToEnd(linePtr, end);
1604    BinaryFormat format;
1605    if (!parseFormat(asmr, linePtr, format))
1606        return;
1607   
1608    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1609            AsmClauseType::IF;
1610    bool included;
1611    bool satisfied = (!negation) ? format==asmr.format: format!=asmr.format;
1612    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1613    {   //
1614        if (!included) // skip clauses (do not perform statements)
1615            asmr.skipClauses();
1616    }
1617}
1618
1619void AsmPseudoOps::doElse(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1620{
1621    if (!checkGarbagesAtEnd(asmr, linePtr))
1622        return;
1623    bool included;
1624    if (asmr.pushClause(pseudoOpPlace, AsmClauseType::ELSE, true, included))
1625    {
1626        if (!included) // skip clauses (do not perform statements)
1627            asmr.skipClauses();
1628    }
1629}
1630
1631void AsmPseudoOps::endIf(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1632{
1633    if (!checkGarbagesAtEnd(asmr, linePtr))
1634        return;
1635    asmr.popClause(pseudoOpPlace, AsmClauseType::IF);
1636}
1637
1638void AsmPseudoOps::doRepeat(Assembler& asmr, const char* pseudoOpPlace,
1639                    const char* linePtr)
1640{
1641    const char* end = asmr.line + asmr.lineSize;
1642    skipSpacesToEnd(linePtr, end);
1643    uint64_t repeatsNum;
1644    bool good = getAbsoluteValueArg(asmr, repeatsNum, linePtr, true);
1645    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1646        return;
1647   
1648    if (asmr.repetitionLevel == 1000)
1649    {
1650        asmr.printError(pseudoOpPlace, "Repetition level is greater than 1000");
1651        return;
1652    }
1653    asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1654    if (repeatsNum == 0)
1655    {   /* skip it */
1656        asmr.skipClauses();
1657        return;
1658    }
1659    /* create repetition (even if only 1 - for correct source position included
1660     * to messages from repetition) */
1661    std::unique_ptr<AsmRepeat> repeat(new AsmRepeat(
1662                asmr.getSourcePos(pseudoOpPlace), repeatsNum));
1663    if (asmr.putRepetitionContent(*repeat))
1664    {   // and input stream filter
1665        std::unique_ptr<AsmInputFilter> newInputFilter(
1666                    new AsmRepeatInputFilter(repeat.release()));
1667        asmr.asmInputFilters.push(newInputFilter.release());
1668        asmr.currentInputFilter = asmr.asmInputFilters.top();
1669        asmr.repetitionLevel++;
1670    }
1671}
1672
1673void AsmPseudoOps::endRepeat(Assembler& asmr, const char* pseudoOpPlace,
1674                   const char* linePtr)
1675{
1676    if (!checkGarbagesAtEnd(asmr, linePtr))
1677        return;
1678    asmr.popClause(pseudoOpPlace, AsmClauseType::REPEAT);
1679}
1680
1681void AsmPseudoOps::doMacro(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1682{
1683    const char* end = asmr.line + asmr.lineSize;
1684    skipSpacesToEnd(linePtr, end);
1685    const char* macroNamePlace = linePtr;
1686    CString macroName = extractSymName(linePtr, end, false);
1687    if (macroName.empty())
1688    {
1689        asmr.printError(macroNamePlace, "Expected macro name");
1690        return;
1691    }
1692    toLowerString(macroName);
1693    /* parse args */
1694    std::vector<AsmMacroArg> args;
1695   
1696    bool good = true;
1697    bool haveVarArg = false;
1698   
1699    if (asmr.macroMap.find(macroName) != asmr.macroMap.end())
1700    {
1701        asmr.printError(macroNamePlace, (std::string("Macro '") + macroName.c_str() +
1702                "' is already defined").c_str());
1703        good = false;
1704    }
1705   
1706    {
1707    std::unordered_set<CString> macroArgSet;
1708    while(linePtr != end)
1709    {
1710        skipSpacesToEnd(linePtr, end);
1711        if (linePtr != end && *linePtr == ',')
1712            skipCharAndSpacesToEnd(linePtr, end);
1713        const char* argPlace = linePtr;
1714        CString argName = extractSymName(linePtr, end, false);
1715        if (argName.empty())
1716        {
1717            asmr.printError(argPlace, "Expected macro argument name");
1718            return; //
1719        }
1720        bool argRequired = false;
1721        bool argVarArgs = false;
1722        bool argGood = true;
1723        std::string defaultArgValue;
1724       
1725        if (!macroArgSet.insert(argName).second)
1726        {   // duplicate!
1727            asmr.printError(argPlace, (std::string("Duplicated macro argument '")+
1728                    argName.c_str()+'\'').c_str());
1729            argGood = false;
1730        }
1731       
1732        skipSpacesToEnd(linePtr, end);
1733        if (linePtr != end && *linePtr == ':')
1734        {   // qualifier
1735            skipCharAndSpacesToEnd(linePtr, end);
1736            //extr
1737            if (linePtr+3 <= end && linePtr[0] == 'r' && linePtr[1] == 'e' &&
1738                    linePtr[2] == 'q') // required
1739            {
1740                argRequired = true;
1741                linePtr += 3;
1742            }
1743            else if (linePtr+6 <= end && ::memcmp(linePtr, "vararg", 6)==0) // required
1744            {
1745                argVarArgs = true;
1746                linePtr += 6;
1747            }
1748            else
1749            {   // otherwise
1750                asmr.printError(linePtr, "Expected qualifier 'req' or 'vararg'");
1751                argGood = false;
1752            }
1753        }
1754        skipSpacesToEnd(linePtr, end);
1755        if (linePtr != end && *linePtr == '=')
1756        {   // parse default value
1757            skipCharAndSpacesToEnd(linePtr, end);
1758            const char* defaultValueStr = linePtr;
1759            if (!asmr.parseMacroArgValue(linePtr, defaultArgValue))
1760            {
1761                good = false;
1762                continue; // error
1763            }
1764            if (argRequired)
1765                asmr.printWarning(defaultValueStr, (std::string(
1766                        "Pointless default value for argument '") +
1767                        argName.c_str()+'\'').c_str());
1768        }
1769       
1770        if (argGood) // push to arguments
1771        {
1772            if (haveVarArg)
1773            {
1774                asmr.printError(argPlace, "Variadic argument must be last");
1775                good = false;
1776            }
1777            else
1778                haveVarArg = argVarArgs;
1779        }
1780        else // not good
1781            good = false;
1782       
1783        if (argGood) // push argument
1784            args.push_back({argName, defaultArgValue, argVarArgs, argRequired});
1785    }
1786    }
1787    if (good)
1788    {   
1789        if (checkPseudoOpName(macroName))
1790        {   // ignore
1791            asmr.printWarning(pseudoOpPlace, (std::string(
1792                        "Attempt to redefine pseudo-op '")+macroName.c_str()+
1793                        "' as macro. Ignoring it...").c_str());
1794            asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
1795            asmr.skipClauses();
1796            return;
1797        }
1798        if (asmr.checkReservedName(macroName))
1799            asmr.printWarning(pseudoOpPlace, (std::string(
1800                    "Attempt to redefine instruction or prefix '")+macroName.c_str()+
1801                    "' as macro.").c_str());
1802        // create a macro
1803        RefPtr<const AsmMacro> macro(new AsmMacro(asmr.getSourcePos(pseudoOpPlace),
1804                        Array<AsmMacroArg>(args.begin(), args.end())));
1805        asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
1806        if (!asmr.putMacroContent(macro.constCast<AsmMacro>()))
1807            return;
1808        asmr.macroMap.insert(std::make_pair(std::move(macroName), std::move(macro)));
1809    }
1810}
1811
1812void AsmPseudoOps::endMacro(Assembler& asmr, const char* pseudoOpPlace,
1813                    const char* linePtr)
1814{
1815    if (!checkGarbagesAtEnd(asmr, linePtr))
1816        return;
1817    asmr.popClause(pseudoOpPlace, AsmClauseType::MACRO);
1818}
1819
1820void AsmPseudoOps::exitMacro(Assembler& asmr, const char* pseudoOpPlace,
1821                   const char* linePtr)
1822{
1823    if (!checkGarbagesAtEnd(asmr, linePtr))
1824        return;
1825   
1826    const AsmInputFilterType type = asmr.currentInputFilter->getType();
1827    if (type == AsmInputFilterType::STREAM)
1828        asmr.printWarning(pseudoOpPlace, "'.exitm' is ignored outside macro content");
1829    else
1830    {
1831        if (type == AsmInputFilterType::REPEAT)
1832            asmr.printWarning(pseudoOpPlace, "Behavior of '.exitm' inside repeat is "
1833                    "undefined. Exiting from repeat...");
1834        asmr.skipClauses(true);
1835    }
1836}
1837
1838void AsmPseudoOps::doIRP(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1839              bool perChar)
1840{
1841    const char* end = asmr.line + asmr.lineSize;
1842    skipSpacesToEnd(linePtr, end);
1843    const char* symNamePlace = linePtr;
1844    CString symName = extractSymName(linePtr, end, false);
1845    if (symName.empty())
1846    {
1847        asmr.printError(symNamePlace, "Expected argument name");
1848        return;
1849    }
1850    /* parse args */
1851    std::vector<CString> symValues;
1852    std::string symValString;
1853   
1854    bool good = true;
1855    skipSpacesToEnd(linePtr, end);
1856    if (linePtr != end && *linePtr == ',')
1857        skipCharAndSpacesToEnd(linePtr, end);
1858   
1859    while(linePtr != end)
1860    {
1861        if (linePtr != end && *linePtr == ',')
1862        {
1863            if (perChar)
1864                symValString.push_back(',');
1865            skipCharAndSpacesToEnd(linePtr, end);
1866        }
1867        std::string symValue;
1868        if (!asmr.parseMacroArgValue(linePtr, symValue))
1869        {
1870            good = false;
1871            continue; // error
1872        }
1873        skipSpacesToEnd(linePtr, end);
1874        if (!perChar)
1875            symValues.push_back(symValue);
1876        else
1877            symValString += symValue;
1878    }
1879   
1880    if (asmr.repetitionLevel == 1000)
1881    {
1882        asmr.printError(pseudoOpPlace, "Repetition level is greater than 1000");
1883        return;
1884    }
1885   
1886    if (symValues.empty())
1887        symValues.push_back("");
1888    if (good)
1889    {
1890        asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1891        std::unique_ptr<AsmIRP> repeat;
1892        if (!perChar)
1893            repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
1894                      symName, Array<CString>(symValues.begin(), symValues.end())));
1895        else // per char
1896            repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
1897                      symName, symValString));
1898       
1899        if (asmr.putRepetitionContent(*repeat))
1900        {   // and input stream filter
1901            std::unique_ptr<AsmInputFilter> newInputFilter(
1902                        new AsmIRPInputFilter(repeat.release()));
1903            asmr.asmInputFilters.push(newInputFilter.release());
1904            asmr.currentInputFilter = asmr.asmInputFilters.top();
1905            asmr.repetitionLevel++;
1906        }
1907    }
1908}
1909
1910void AsmPseudoOps::purgeMacro(Assembler& asmr, const char* linePtr)
1911{
1912    const char* end = asmr.line+asmr.lineSize;
1913    skipSpacesToEnd(linePtr, end);
1914    const char* macroNamePlace = linePtr;
1915    CString macroName = extractSymName(linePtr, end, false);
1916    bool good = true;
1917    if (macroName.empty())
1918    {
1919        asmr.printError(macroNamePlace, "Expected macro name");
1920        good = false;
1921    }
1922    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1923        return;
1924    toLowerString(macroName); // macro name is lowered
1925    if (!asmr.macroMap.erase(macroName))
1926        asmr.printWarning(macroNamePlace, (std::string("Macro '")+macroName.c_str()+
1927                "' already doesn't exist").c_str());
1928}
1929
1930void AsmPseudoOps::undefSymbol(Assembler& asmr, const char* linePtr)
1931{
1932    const char* end = asmr.line+asmr.lineSize;
1933    skipSpacesToEnd(linePtr, end);
1934    const char* symNamePlace = linePtr;
1935    CString symName = extractSymName(linePtr, end, false);
1936    bool good = true;
1937    if (symName.empty())
1938    {
1939        asmr.printError(symNamePlace, "Expected symbol name");
1940        good = false;
1941    }
1942    else if (symName == ".")
1943    {
1944        asmr.printError(symNamePlace, "Symbol '.' can not be undefined");
1945        good = false;
1946    }
1947    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1948        return;
1949   
1950    auto it = asmr.symbolMap.find(symName);
1951    if (it == asmr.symbolMap.end() ||
1952        (!it->second.hasValue && it->second.expression==nullptr))
1953        asmr.printWarning(symNamePlace, (std::string("Symbol '") + symName.c_str() +
1954                "' already doesn't exist").c_str());
1955    else if (it->second.occurrencesInExprs.empty())
1956        asmr.symbolMap.erase(it);
1957    else
1958        it->second.undefine();
1959}
1960
1961void AsmPseudoOps::setAbsoluteOffset(Assembler& asmr, const char* linePtr)
1962{
1963    const char* end = asmr.line+asmr.lineSize;
1964    asmr.initializeOutputFormat();
1965    skipSpacesToEnd(linePtr, end);
1966    uint64_t value = 0;
1967    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
1968    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1969        return;
1970    asmr.currentSection = ASMSECT_ABS;
1971    asmr.currentOutPos = value;
1972}
1973
1974void AsmPseudoOps::doDefRegVar(Assembler& asmr, const char* pseudoOpPlace,
1975                       const char* linePtr)
1976{
1977    const char* end = asmr.line+asmr.lineSize;
1978    asmr.initializeOutputFormat();
1979   
1980    if (!asmr.isWriteableSection() || !asmr.isAddressableSection())
1981    {
1982        asmr.printError(pseudoOpPlace, "RegVar definition can be in "
1983                    "writable and addressable section");
1984        return;
1985    }
1986    AsmSection& section = asmr.sections[asmr.currentSection];
1987   
1988    do {
1989        skipSpacesToEnd(linePtr, end);
1990        const char* regNamePlace = linePtr;
1991        CString name = extractSymName(linePtr, end, false);
1992        bool good = true;
1993        if (name.empty())
1994        {
1995            asmr.printError(regNamePlace, "Expected reg-var name");
1996            good = false;
1997        }
1998        skipSpacesToEnd(linePtr, end);
1999        if (linePtr==end || *linePtr!=':')
2000        {
2001            asmr.printError(linePtr, "Expected colon after reg-var");
2002            continue;
2003        }
2004        linePtr++;
2005        skipSpacesToEnd(linePtr, end);
2006        AsmRegVar var = { 0, 1 };
2007        if (!asmr.isaAssembler->parseRegisterType(linePtr, end, var.type))
2008        {
2009            asmr.printError(linePtr, "Expected name of register type");
2010            good = false;
2011        }
2012        skipSpacesToEnd(linePtr, end);
2013       
2014        if (linePtr!=end && *linePtr!=',')
2015        {
2016            if (*linePtr!=':')
2017            {
2018                asmr.printError(linePtr, "Expected colon after reg-var");
2019                continue;
2020            }
2021            linePtr++;
2022            skipSpacesToEnd(linePtr, end);
2023            uint64_t regSize;
2024            if (!getAbsoluteValueArg(asmr, regSize, linePtr, true))
2025                continue;
2026            GPUArchitecture arch = getGPUArchitectureFromDeviceType(asmr.deviceType);
2027            if (regSize==0)
2028            {
2029                asmr.printError(linePtr, "Size of reg-var is zero");
2030                good = false;
2031            }
2032            if (regSize>getGPUMaxRegistersNum(arch, regSize, 0))
2033            {
2034                asmr.printError(linePtr, "Size of reg-var out of max number of registers");
2035                good = false;
2036            }
2037            var.size = regSize;
2038        }
2039       
2040        if (!good)
2041            continue;
2042       
2043        if (!section.addRegVar(name, var))
2044            asmr.printError(regNamePlace, (std::string("Reg-var '")+name.c_str()+
2045                        "' was already defined").c_str());
2046       
2047    } while(skipCommaForMultipleArgs(asmr, linePtr));
2048   
2049    checkGarbagesAtEnd(asmr, linePtr);
2050}
2051
2052void AsmPseudoOps::ignoreString(Assembler& asmr, const char* linePtr)
2053{
2054    const char* end = asmr.line+asmr.lineSize;
2055    skipSpacesToEnd(linePtr, end);
2056    std::string out;
2057    if (asmr.parseString(out, linePtr))
2058        checkGarbagesAtEnd(asmr, linePtr);
2059}
2060
2061bool AsmPseudoOps::checkPseudoOpName(const CString& string)
2062{
2063    if (string.empty() || string[0] != '.')
2064        return false;
2065    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2066                    sizeof(pseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
2067                   CStringLess()) - pseudoOpNamesTbl;
2068    if (pseudoOp < sizeof(pseudoOpNamesTbl)/sizeof(char*))
2069        return true;
2070    if (AsmGalliumPseudoOps::checkPseudoOpName(string))
2071        return true;
2072    if (AsmAmdPseudoOps::checkPseudoOpName(string))
2073        return true;
2074    if (AsmAmdCL2PseudoOps::checkPseudoOpName(string))
2075        return true;
2076    if (AsmROCmPseudoOps::checkPseudoOpName(string))
2077        return true;
2078    return false;
2079}
2080
2081};
2082
2083void Assembler::parsePseudoOps(const CString& firstName,
2084       const char* stmtPlace, const char* linePtr)
2085{
2086    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2087                    sizeof(pseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
2088                   CStringLess()) - pseudoOpNamesTbl;
2089   
2090    switch(pseudoOp)
2091    {
2092        case ASMOP_32BIT:
2093        case ASMOP_64BIT:
2094            AsmPseudoOps::setBitness(*this, linePtr, pseudoOp == ASMOP_64BIT);
2095            break;
2096        case ASMOP_ABORT:
2097            printError(stmtPlace, "Aborted!");
2098            endOfAssembly = true;
2099            break;
2100        case ASMOP_ALIGN:
2101        case ASMOP_BALIGN:
2102            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr);
2103            break;
2104        case ASMOP_ALTMACRO:
2105            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2106                alternateMacro = true;
2107            break;
2108        case ASMOP_ARCH:
2109            AsmPseudoOps::setGPUArchitecture(*this, linePtr);
2110            break;
2111        case ASMOP_ASCII:
2112            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr);
2113            break;
2114        case ASMOP_ASCIZ:
2115            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2116            break;
2117        case ASMOP_BALIGNL:
2118            AsmPseudoOps::doAlignWord<uint32_t>(*this, stmtPlace, linePtr);
2119            break;
2120        case ASMOP_BALIGNW:
2121            AsmPseudoOps::doAlignWord<uint16_t>(*this, stmtPlace, linePtr);
2122            break;
2123        case ASMOP_BUGGYFPLIT:
2124            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2125                buggyFPLit = true;
2126            break;
2127        case ASMOP_BYTE:
2128            AsmPseudoOps::putIntegers<cxbyte>(*this, stmtPlace, linePtr);
2129            break;
2130        case ASMOP_AMD:
2131        case ASMOP_AMDCL2:
2132        case ASMOP_RAWCODE:
2133        case ASMOP_GALLIUM:
2134        case ASMOP_ROCM:
2135            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2136            {
2137                if (formatHandler!=nullptr)
2138                    printError(linePtr, "Output format type is already defined");
2139                else
2140                    format = (pseudoOp == ASMOP_GALLIUM) ? BinaryFormat::GALLIUM :
2141                        (pseudoOp == ASMOP_AMD) ? BinaryFormat::AMD :
2142                        (pseudoOp == ASMOP_AMDCL2) ? BinaryFormat::AMDCL2 :
2143                        (pseudoOp == ASMOP_ROCM) ? BinaryFormat::ROCM :
2144                        BinaryFormat::RAWCODE;
2145            }
2146            break;
2147        case ASMOP_DATA:
2148            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2149            break;
2150        case ASMOP_DOUBLE:
2151            AsmPseudoOps::putFloats<uint64_t>(*this, stmtPlace, linePtr);
2152            break;
2153        case ASMOP_ELSE:
2154            AsmPseudoOps::doElse(*this, stmtPlace, linePtr);
2155            break;
2156        case ASMOP_ELSEIF:
2157            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2158                      IfIntComp::NOT_EQUAL, true);
2159            break;
2160        case ASMOP_ELSEIF32:
2161            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, true);
2162            break;
2163        case ASMOP_ELSEIF64:
2164            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, true);
2165            break;
2166        case ASMOP_ELSEIFARCH:
2167            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, true);
2168            break;
2169        case ASMOP_ELSEIFB:
2170            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, true);
2171            break;
2172        case ASMOP_ELSEIFC:
2173            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, true);
2174            break;
2175        case ASMOP_ELSEIFDEF:
2176            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, true);
2177            break;
2178        case ASMOP_ELSEIFEQ:
2179            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2180                      IfIntComp::EQUAL, true);
2181            break;
2182        case ASMOP_ELSEIFEQS:
2183            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, true);
2184            break;
2185        case ASMOP_ELSEIFFMT:
2186            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, true);
2187            break;
2188        case ASMOP_ELSEIFGE:
2189            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2190                      IfIntComp::GREATER_EQUAL, true);
2191            break;
2192        case ASMOP_ELSEIFGPU:
2193            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, true);
2194            break;
2195        case ASMOP_ELSEIFGT:
2196            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2197                      IfIntComp::GREATER, true);
2198            break;
2199        case ASMOP_ELSEIFLE:
2200            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2201                      IfIntComp::LESS_EQUAL, true);
2202            break;
2203        case ASMOP_ELSEIFLT:
2204            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2205                      IfIntComp::LESS, true);
2206            break;
2207        case ASMOP_ELSEIFNARCH:
2208            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, true);
2209            break;
2210        case ASMOP_ELSEIFNB:
2211            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, true);
2212            break;
2213        case ASMOP_ELSEIFNC:
2214            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, true);
2215            break;
2216        case ASMOP_ELSEIFNOTDEF:
2217        case ASMOP_ELSEIFNDEF:
2218            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, true);
2219            break;
2220        case ASMOP_ELSEIFNE:
2221            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2222                      IfIntComp::NOT_EQUAL, true);
2223            break;
2224        case ASMOP_ELSEIFNES:
2225            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, true);
2226            break;
2227        case ASMOP_ELSEIFNFMT:
2228            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, true);
2229            break;
2230        case ASMOP_ELSEIFNGPU:
2231            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, true);
2232            break;
2233        case ASMOP_END:
2234            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2235                endOfAssembly = true;
2236            break;
2237        case ASMOP_ENDIF:
2238            AsmPseudoOps::endIf(*this, stmtPlace, linePtr);
2239            break;
2240        case ASMOP_ENDM:
2241            AsmPseudoOps::endMacro(*this, stmtPlace, linePtr);
2242            break;
2243        case ASMOP_ENDR:
2244            AsmPseudoOps::endRepeat(*this, stmtPlace, linePtr);
2245            break;
2246        case ASMOP_EQU:
2247        case ASMOP_SET:
2248            AsmPseudoOps::setSymbol(*this, linePtr);
2249            break;
2250        case ASMOP_EQUIV:
2251            AsmPseudoOps::setSymbol(*this, linePtr, false);
2252            break;
2253        case ASMOP_EQV:
2254            AsmPseudoOps::setSymbol(*this, linePtr, false, true);
2255            break;
2256        case ASMOP_ERR:
2257            printError(stmtPlace, ".err encountered");
2258            break;
2259        case ASMOP_ERROR:
2260            AsmPseudoOps::doError(*this, stmtPlace, linePtr);
2261            break;
2262        case ASMOP_EXITM:
2263            AsmPseudoOps::exitMacro(*this, stmtPlace, linePtr);
2264            break;
2265        case ASMOP_EXTERN:
2266            AsmPseudoOps::ignoreExtern(*this, linePtr);
2267            break;
2268        case ASMOP_FAIL:
2269            AsmPseudoOps::doFail(*this, stmtPlace, linePtr);
2270            break;
2271        case ASMOP_FILE:
2272            printWarning(stmtPlace, "'.file' is ignored by this assembler.");
2273            break;
2274        case ASMOP_FILL:
2275            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, false);
2276            break;
2277        case ASMOP_FILLQ:
2278            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, true);
2279            break;
2280        case ASMOP_FLOAT:
2281            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2282            break;
2283        case ASMOP_FORMAT:
2284            AsmPseudoOps::setOutFormat(*this, linePtr);
2285            break;
2286        case ASMOP_GLOBAL:
2287        case ASMOP_GLOBL:
2288            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_GLOBAL);
2289            break;
2290        case ASMOP_GPU:
2291            AsmPseudoOps::setGPUDevice(*this, linePtr);
2292            break;
2293        case ASMOP_HALF:
2294            AsmPseudoOps::putFloats<uint16_t>(*this, stmtPlace, linePtr);
2295            break;
2296        case ASMOP_HWORD:
2297            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2298            break;
2299        case ASMOP_IF:
2300            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2301                      IfIntComp::NOT_EQUAL, false);
2302            break;
2303        case ASMOP_IF32:
2304            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, false);
2305            break;
2306        case ASMOP_IF64:
2307            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, false);
2308            break;
2309        case ASMOP_IFARCH:
2310            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, false);
2311            break;
2312        case ASMOP_IFB:
2313            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, false);
2314            break;
2315        case ASMOP_IFC:
2316            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, false);
2317            break;
2318        case ASMOP_IFDEF:
2319            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, false);
2320            break;
2321        case ASMOP_IFEQ:
2322            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2323                      IfIntComp::EQUAL, false);
2324            break;
2325        case ASMOP_IFEQS:
2326            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, false);
2327            break;
2328        case ASMOP_IFFMT:
2329            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, false);
2330            break;
2331        case ASMOP_IFGE:
2332            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2333                      IfIntComp::GREATER_EQUAL, false);
2334            break;
2335        case ASMOP_IFGPU:
2336            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, false);
2337            break;
2338        case ASMOP_IFGT:
2339            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2340                      IfIntComp::GREATER, false);
2341            break;
2342        case ASMOP_IFLE:
2343            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2344                      IfIntComp::LESS_EQUAL, false);
2345            break;
2346        case ASMOP_IFLT:
2347            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2348                      IfIntComp::LESS, false);
2349            break;
2350        case ASMOP_IFNARCH:
2351            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, false);
2352            break;
2353        case ASMOP_IFNB:
2354            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, false);
2355            break;
2356        case ASMOP_IFNC:
2357            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, false);
2358            break;
2359        case ASMOP_IFNDEF:
2360        case ASMOP_IFNOTDEF:
2361            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, false);
2362            break;
2363        case ASMOP_IFNE:
2364            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2365                      IfIntComp::NOT_EQUAL, false);
2366            break;
2367        case ASMOP_IFNES:
2368            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, false);
2369            break;
2370        case ASMOP_IFNFMT:
2371            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, false);
2372            break;
2373        case ASMOP_IFNGPU:
2374            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, false);
2375            break;
2376        case ASMOP_INCBIN:
2377            AsmPseudoOps::includeBinFile(*this, stmtPlace, linePtr);
2378            break;
2379        case ASMOP_INCLUDE:
2380            AsmPseudoOps::includeFile(*this, stmtPlace, linePtr);
2381            break;
2382        case ASMOP_IRP:
2383            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, false);
2384            break;
2385        case ASMOP_IRPC:
2386            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, true);
2387            break;
2388        case ASMOP_INT:
2389        case ASMOP_LONG:
2390            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2391            break;
2392        case ASMOP_KERNEL:
2393            AsmPseudoOps::goToKernel(*this, stmtPlace, linePtr);
2394            break;
2395        case ASMOP_LFLAGS:
2396            printWarning(stmtPlace, "'.lflags' is ignored by this assembler.");
2397            break;
2398        case ASMOP_LINE:
2399        case ASMOP_LN:
2400            printWarning(stmtPlace, "'.line' is ignored by this assembler.");
2401            break;
2402        case ASMOP_LOCAL:
2403            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_LOCAL);
2404            break;
2405        case ASMOP_MACRO:
2406            AsmPseudoOps::doMacro(*this, stmtPlace, linePtr);
2407            break;
2408        case ASMOP_MAIN:
2409            AsmPseudoOps::goToMain(*this, stmtPlace, linePtr);
2410            break;
2411        case ASMOP_NOALTMACRO:
2412            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2413                alternateMacro = false;
2414            break;
2415        case ASMOP_NOBUGGYFPLIT:
2416            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2417                buggyFPLit = false;
2418            break;
2419        case ASMOP_OCTA:
2420            AsmPseudoOps::putUInt128s(*this, stmtPlace, linePtr);
2421            break;
2422        case ASMOP_OFFSET:
2423            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2424            break;
2425        case ASMOP_ORG:
2426            AsmPseudoOps::doOrganize(*this, linePtr);
2427            break;
2428        case ASMOP_P2ALIGN:
2429            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr, true);
2430            break;
2431        case ASMOP_PRINT:
2432            AsmPseudoOps::doPrint(*this, linePtr);
2433            break;
2434        case ASMOP_PURGEM:
2435            AsmPseudoOps::purgeMacro(*this, linePtr);
2436            break;
2437        case ASMOP_QUAD:
2438            AsmPseudoOps::putIntegers<uint64_t>(*this, stmtPlace, linePtr);
2439            break;
2440        case ASMOP_REG:
2441            AsmPseudoOps::doDefRegVar(*this, stmtPlace, linePtr);
2442            break;
2443        case ASMOP_REPT:
2444            AsmPseudoOps::doRepeat(*this, stmtPlace, linePtr);
2445            break;
2446        case ASMOP_RODATA:
2447            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2448            break;
2449        case ASMOP_SECTION:
2450            AsmPseudoOps::goToSection(*this, stmtPlace, linePtr);
2451            break;
2452        case ASMOP_SHORT:
2453            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2454            break;
2455        case ASMOP_SINGLE:
2456            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2457            break;
2458        case ASMOP_SIZE:
2459            AsmPseudoOps::setSymbolSize(*this, linePtr);
2460            break;
2461        case ASMOP_SKIP:
2462        case ASMOP_SPACE:
2463            AsmPseudoOps::doSkip(*this, stmtPlace, linePtr);
2464            break;
2465        case ASMOP_STRING:
2466            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2467            break;
2468        case ASMOP_STRING16:
2469            AsmPseudoOps::putStringsToInts<uint16_t>(*this, stmtPlace, linePtr);
2470            break;
2471        case ASMOP_STRING32:
2472            AsmPseudoOps::putStringsToInts<uint32_t>(*this, stmtPlace, linePtr);
2473            break;
2474        case ASMOP_STRING64:
2475            AsmPseudoOps::putStringsToInts<uint64_t>(*this, stmtPlace, linePtr);
2476            break;
2477        case ASMOP_STRUCT:
2478            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2479            break;
2480        case ASMOP_TEXT:
2481            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2482            break;
2483        case ASMOP_SBTTL:
2484        case ASMOP_TITLE:
2485        case ASMOP_VERSION:
2486            AsmPseudoOps::ignoreString(*this, linePtr);
2487            break;
2488        case ASMOP_UNDEF:
2489            AsmPseudoOps::undefSymbol(*this, linePtr);
2490            break;
2491        case ASMOP_WARNING:
2492            AsmPseudoOps::doWarning(*this, stmtPlace, linePtr);
2493            break;
2494        case ASMOP_WEAK:
2495            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_WEAK);
2496            break;
2497        case ASMOP_WORD:
2498            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2499            break;
2500        default:
2501        {
2502            bool isGalliumPseudoOp = AsmGalliumPseudoOps::checkPseudoOpName(firstName);
2503            bool isAmdPseudoOp = AsmAmdPseudoOps::checkPseudoOpName(firstName);
2504            bool isAmdCL2PseudoOp = AsmAmdCL2PseudoOps::checkPseudoOpName(firstName);
2505            bool isROCmPseudoOp = AsmROCmPseudoOps::checkPseudoOpName(firstName);
2506            if (isGalliumPseudoOp || isAmdPseudoOp || isAmdCL2PseudoOp)
2507            {   // initialize only if gallium pseudo-op or AMD pseudo-op
2508                initializeOutputFormat();
2509                /// try to parse
2510                if (!formatHandler->parsePseudoOp(firstName, stmtPlace, linePtr))
2511                {   // check other
2512                    if (format != BinaryFormat::GALLIUM)
2513                    {   // check gallium pseudo-op
2514                        if (isGalliumPseudoOp)
2515                        {
2516                            printError(stmtPlace, "Gallium pseudo-op can be defined "
2517                                    "only in Gallium format code");
2518                            break;
2519                        }
2520                    }
2521                    if (format != BinaryFormat::AMD)
2522                    {   // check amd pseudo-op
2523                        if (isAmdPseudoOp)
2524                        {
2525                            printError(stmtPlace, "AMD pseudo-op can be defined only in "
2526                                    "AMD format code");
2527                            break;
2528                        }
2529                    }
2530                    if (format != BinaryFormat::AMDCL2)
2531                    {   // check amd pseudo-op
2532                        if (isAmdCL2PseudoOp)
2533                        {
2534                            printError(stmtPlace, "AMDCL2 pseudo-op can be defined only in "
2535                                    "AMDCL2 format code");
2536                            break;
2537                        }
2538                    }
2539                    if (format != BinaryFormat::ROCM)
2540                    {   // check rocm pseudo-op
2541                        if (isROCmPseudoOp)
2542                        {
2543                            printError(stmtPlace, "ROCm pseudo-op can be defined "
2544                                    "only in ROCm format code");
2545                            break;
2546                        }
2547                    }
2548                }
2549            }
2550            else if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
2551                printError(stmtPlace, "This is neither pseudo-op and nor macro");
2552            break;
2553        }
2554    }
2555}
2556
2557/* skipping clauses */
2558bool Assembler::skipClauses(bool exitm)
2559{
2560    const cxuint clauseLevel = clauses.size();
2561    AsmClauseType topClause = (!clauses.empty()) ? clauses.top().type :
2562            AsmClauseType::IF;
2563    const bool isTopIfClause = (topClause == AsmClauseType::IF ||
2564            topClause == AsmClauseType::ELSEIF || topClause == AsmClauseType::ELSE);
2565    bool good = true;
2566    const size_t inputFilterTop = asmInputFilters.size();
2567    while (exitm || clauses.size() >= clauseLevel)
2568    {
2569        if (!readLine())
2570            break;
2571        // if exit from macro mode, exit when macro filter exits
2572        if (exitm && inputFilterTop > asmInputFilters.size())
2573        {   // set lineAlreadyRead - next line after skipped region read will be read
2574            lineAlreadyRead  = true;
2575            break; // end of macro,
2576        }
2577       
2578        const char* linePtr = line;
2579        const char* end = line+lineSize;
2580        skipSpacesAndLabels(linePtr, end);
2581        const char* stmtPlace = linePtr;
2582        if (linePtr == end || *linePtr != '.')
2583            continue;
2584       
2585        CString pseudoOpName = extractSymName(linePtr, end, false);
2586        toLowerString(pseudoOpName);
2587       
2588        const size_t pseudoOp = binaryFind(offlinePseudoOpNamesTbl,
2589               offlinePseudoOpNamesTbl + sizeof(offlinePseudoOpNamesTbl)/sizeof(char*),
2590               pseudoOpName.c_str()+1, CStringLess()) - offlinePseudoOpNamesTbl;
2591       
2592        // any conditional inside macro or repeat will be ignored
2593        bool insideMacroOrRepeat = !clauses.empty() && 
2594            (clauses.top().type == AsmClauseType::MACRO ||
2595                    clauses.top().type == AsmClauseType::REPEAT);
2596        switch(pseudoOp)
2597        {
2598            case ASMCOP_ENDIF:
2599                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2600                    good = false;   // if endif have garbages
2601                else if (!insideMacroOrRepeat)
2602                    if (!popClause(stmtPlace, AsmClauseType::IF))
2603                        good = false;
2604                break;
2605            case ASMCOP_ENDM:
2606                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2607                    good = false;   // if .endm have garbages
2608                else if (!popClause(stmtPlace, AsmClauseType::MACRO))
2609                    good = false;
2610                break;
2611            case ASMCOP_ENDR:
2612                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2613                    good = false;   // if .endr have garbages
2614                else if (!popClause(stmtPlace, AsmClauseType::REPEAT))
2615                    good = false;
2616                break;
2617            case ASMCOP_ELSE:
2618            case ASMCOP_ELSEIFARCH:
2619            case ASMCOP_ELSEIF:
2620            case ASMCOP_ELSEIF32:
2621            case ASMCOP_ELSEIF64:
2622            case ASMCOP_ELSEIFB:
2623            case ASMCOP_ELSEIFC:
2624            case ASMCOP_ELSEIFDEF:
2625            case ASMCOP_ELSEIFEQ:
2626            case ASMCOP_ELSEIFEQS:
2627            case ASMCOP_ELSEIFFMT:
2628            case ASMCOP_ELSEIFGE:
2629            case ASMCOP_ELSEIFGPU:
2630            case ASMCOP_ELSEIFGT:
2631            case ASMCOP_ELSEIFLE:
2632            case ASMCOP_ELSEIFLT:
2633            case ASMCOP_ELSEIFNARCH:
2634            case ASMCOP_ELSEIFNB:
2635            case ASMCOP_ELSEIFNC:
2636            case ASMCOP_ELSEIFNDEF:
2637            case ASMCOP_ELSEIFNE:
2638            case ASMCOP_ELSEIFNES:
2639            case ASMCOP_ELSEIFNFMT:
2640            case ASMCOP_ELSEIFNGPU:
2641            case ASMCOP_ELSEIFNOTDEF:
2642                if (pseudoOp == ASMCOP_ELSE &&
2643                            !AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2644                    good = false; // if .else have garbages
2645                else if (!insideMacroOrRepeat)
2646                {
2647                    if (!exitm && clauseLevel == clauses.size() && isTopIfClause)
2648                    {   /* set lineAlreadyRead - next line after skipped region read
2649                         * will be read */
2650                        lineAlreadyRead = true; // read
2651                        return good; // do exit
2652                    }
2653                    if (!pushClause(stmtPlace, (pseudoOp==ASMCOP_ELSE ?
2654                                AsmClauseType::ELSE : AsmClauseType::ELSEIF)))
2655                        good = false;
2656                }
2657                break;
2658            case ASMCOP_IF:
2659            case ASMCOP_IFARCH:
2660            case ASMCOP_IF32:
2661            case ASMCOP_IF64:
2662            case ASMCOP_IFB:
2663            case ASMCOP_IFC:
2664            case ASMCOP_IFDEF:
2665            case ASMCOP_IFEQ:
2666            case ASMCOP_IFEQS:
2667            case ASMCOP_IFFMT:
2668            case ASMCOP_IFGE:
2669            case ASMCOP_IFGPU:
2670            case ASMCOP_IFGT:
2671            case ASMCOP_IFLE:
2672            case ASMCOP_IFLT:
2673            case ASMCOP_IFNARCH:
2674            case ASMCOP_IFNB:
2675            case ASMCOP_IFNC:
2676            case ASMCOP_IFNDEF:
2677            case ASMCOP_IFNE:
2678            case ASMCOP_IFNES:
2679            case ASMCOP_IFNFMT:
2680            case ASMCOP_IFNGPU:
2681            case ASMCOP_IFNOTDEF:
2682                if (!insideMacroOrRepeat)
2683                {
2684                    if (!pushClause(stmtPlace, AsmClauseType::IF))
2685                        good = false;
2686                }
2687                break;
2688            case ASMCOP_MACRO:
2689                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
2690                    good = false;
2691                break;
2692            case ASMCOP_IRP:
2693            case ASMCOP_IRPC:
2694            case ASMCOP_REPT:
2695                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
2696                    good = false;
2697                break;
2698            default:
2699                break;
2700        }
2701    }
2702    return good;
2703}
2704
2705bool Assembler::putMacroContent(RefPtr<AsmMacro> macro)
2706{
2707    const cxuint clauseLevel = clauses.size();
2708    bool good = true;
2709    while (clauses.size() >= clauseLevel)
2710    {
2711        if (!readLine())
2712        {
2713            good = false;
2714            break;
2715        }
2716       
2717        const char* linePtr = line;
2718        const char* end = line+lineSize;
2719        skipSpacesAndLabels(linePtr, end);
2720        const char* stmtPlace = linePtr;
2721        if (linePtr == end || *linePtr != '.')
2722        {
2723            macro->addLine(currentInputFilter->getMacroSubst(),
2724                  currentInputFilter->getSource(),
2725                  currentInputFilter->getColTranslations(), lineSize, line);
2726            continue;
2727        }
2728       
2729        CString pseudoOpName = extractSymName(linePtr, end, false);
2730        toLowerString(pseudoOpName);
2731       
2732        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
2733               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
2734               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
2735               macroRepeatPseudoOpNamesTbl;
2736        switch(pseudoOp)
2737        {
2738            case ASMMROP_ENDM:
2739                if (!popClause(stmtPlace, AsmClauseType::MACRO))
2740                    good = false;
2741                break;
2742            case ASMMROP_ENDR:
2743                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
2744                    good = false;
2745                break;
2746            case ASMMROP_MACRO:
2747                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
2748                    good = false;
2749                break;
2750            case ASMMROP_IRP:
2751            case ASMMROP_IRPC:
2752            case ASMMROP_REPT:
2753                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
2754                    good = false;
2755                break;
2756            default:
2757                break;
2758        }
2759        if (pseudoOp != ASMMROP_ENDM || clauses.size() >= clauseLevel)
2760            macro->addLine(currentInputFilter->getMacroSubst(),
2761                  currentInputFilter->getSource(),
2762                  currentInputFilter->getColTranslations(), lineSize, line);
2763    }
2764    return good;
2765}
2766
2767bool Assembler::putRepetitionContent(AsmRepeat& repeat)
2768{
2769    const cxuint clauseLevel = clauses.size();
2770    bool good = true;
2771    while (clauses.size() >= clauseLevel)
2772    {
2773        if (!readLine())
2774        {
2775            good = false;
2776            break;
2777        }
2778       
2779        const char* linePtr = line;
2780        const char* end = line+lineSize;
2781        skipSpacesAndLabels(linePtr, end);
2782        const char* stmtPlace = linePtr;
2783        if (linePtr == end || *linePtr != '.')
2784        {
2785            repeat.addLine(currentInputFilter->getMacroSubst(),
2786               currentInputFilter->getSource(), currentInputFilter->getColTranslations(),
2787               lineSize, line);
2788            continue;
2789        }
2790       
2791        CString pseudoOpName = extractSymName(linePtr, end, false);
2792        toLowerString(pseudoOpName);
2793        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
2794               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
2795               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
2796               macroRepeatPseudoOpNamesTbl;
2797        switch(pseudoOp)
2798        {
2799            case ASMMROP_ENDM:
2800                if (!popClause(stmtPlace, AsmClauseType::MACRO))
2801                    good = false;
2802                break;
2803            case ASMMROP_ENDR:
2804                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
2805                    good = false;
2806                break;
2807            case ASMMROP_MACRO:
2808                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
2809                    good = false;
2810                break;
2811            case ASMMROP_IRP:
2812            case ASMMROP_IRPC:
2813            case ASMMROP_REPT:
2814                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
2815                    good = false;
2816                break;
2817            default:
2818                break;
2819        }
2820        if (pseudoOp != ASMMROP_ENDR || clauses.size() >= clauseLevel)
2821            repeat.addLine(currentInputFilter->getMacroSubst(),
2822                   currentInputFilter->getSource(),
2823                   currentInputFilter->getColTranslations(), lineSize, line);
2824    }
2825    return good;
2826}
Note: See TracBrowser for help on using the repository browser.