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

Last change on this file since 3639 was 3639, checked in by matszpk, 2 years ago

CLRadeonExtender: Asm: Missing line (for '.while' pseudo-op).

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