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

Last change on this file since 3631 was 3631, checked in by matszpk, 3 years ago

CLRadeonExtender: Asm: Tentative implementation of '.for' pseudo-op (repetition).

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