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

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

CLRadeonExtender: Asm: Fixed '.32bit' and '.64bit' pseudo-op handling.

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