source: CLRX/CLRadeonExtender/trunk/amdasm/Assembler.cpp @ 3773

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

CLRadeonExtender: Asm: Try later evaluate expressions while setting symbol value as resolving symbols and targets (setSymbol method).

File size: 104.9 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 <cassert>
23#include <fstream>
24#include <vector>
25#include <stack>
26#include <deque>
27#include <utility>
28#include <algorithm>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/utils/MemAccess.h>
31#include <CLRX/utils/GPUId.h>
32#include <CLRX/amdasm/Assembler.h>
33#include "AsmInternals.h"
34
35#define THIS_FAIL_BY_ERROR(PLACE, STRING) \
36    { \
37        printError(PLACE, STRING); \
38        return false; \
39    }
40
41#define THIS_NOTGOOD_BY_ERROR(PLACE, STRING) \
42    { \
43        printError(PLACE, STRING); \
44        good = false; \
45    }
46
47using namespace CLRX;
48
49// Assembler Exception costuctor
50AsmException::AsmException(const std::string& message) : Exception(message)
51{ }
52
53// copy constructor - includes usageHandler copying
54AsmSection::AsmSection(const AsmSection& section)
55{
56    name = section.name;
57    kernelId = section.kernelId;
58    type = section.type;
59    flags = section.flags;
60    alignment = section.alignment;
61    size = section.size;
62    content = section.content;
63    relSpace = section.relSpace;
64    relAddress = section.relAddress;
65   
66    if (section.usageHandler!=nullptr)
67        usageHandler.reset(section.usageHandler->copy());
68    codeFlow = section.codeFlow;
69}
70
71// copy assignment - includes usageHandler copying
72AsmSection& AsmSection::operator=(const AsmSection& section)
73{
74    name = section.name;
75    kernelId = section.kernelId;
76    type = section.type;
77    flags = section.flags;
78    alignment = section.alignment;
79    size = section.size;
80    content = section.content;
81    relSpace = section.relSpace;
82    relAddress = section.relAddress;
83   
84    if (section.usageHandler!=nullptr)
85        usageHandler.reset(section.usageHandler->copy());
86    codeFlow = section.codeFlow;
87    return *this;
88}
89
90// open code region - add new code region if needed
91// called when kernel label encountered or region for this kernel begins
92void AsmKernel::openCodeRegion(size_t offset)
93{
94    if (!codeRegions.empty() && codeRegions.back().second == SIZE_MAX)
95        return;
96    if (codeRegions.empty() || codeRegions.back().first != offset)
97    {
98        if (codeRegions.empty() || codeRegions.back().second != offset)
99            codeRegions.push_back({ offset, SIZE_MAX });
100        else    // set last region as not closed
101            codeRegions.back().second = SIZE_MAX;
102    }
103}
104
105// open code region - set end of region or if empty remove obsolete code region
106// called when new kernel label encountered or region for this kernel ends
107void AsmKernel::closeCodeRegion(size_t offset)
108{
109    if (codeRegions.empty())
110        codeRegions.push_back({ size_t(0), SIZE_MAX });
111    else if (codeRegions.back().second == SIZE_MAX) // only if not closed
112    {
113        codeRegions.back().second = offset;
114        if (codeRegions.back().first == codeRegions.back().second)
115            codeRegions.pop_back(); // remove empty region
116    }
117}
118
119/* table of token characters
120 * value for character means:
121 * 7 bit - this character with previous character with this same
122 *   (7 lower bits) continues token
123 * 0-7 bits - class of token */
124const cxbyte CLRX::tokenCharTable[96] =
125{
126    //' '   '!'   '"'   '#'   '$'   '%'   '&'   '''
127    0x00, 0x01, 0x02, 0x03, 0x90, 0x85, 0x06, 0x07,
128    //'('   ')'   '*'   '+'   ','   '-'   '.'   '/'
129    0x88, 0x88, 0x8a, 0x0b, 0x0c, 0x8d, 0x90, 0x0f,
130    //'0'   '1'   '2'   '3'   '4'   '5'   '6'   '7' 
131    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
132    //'8'   '9'   ':'   ';'   '<'   '='   '>'   '?'
133    0x90, 0x90, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
134    //'@'   'A'   'B'   'C'   'D'   'E'   'F'   'G'
135    0x26, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
136    //'H'   'I'   'J'   'K'   'L'   'M'   'N'   'O'
137    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
138    //'P'   'Q'   'R'   'S'   'T'   'U'   'V'   'W'
139    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
140    //'X'   'Y'   'Z'   '['   '\'   ']'   '^'   '_'
141    0x90, 0x90, 0x90, 0x91, 0x92, 0x93, 0x14, 0x90,
142    //'`'   'a'   'b'   'c'   'd'   'e'   'f'   'g'
143    0x16, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
144    //'h'   'i'   'j'   'k'   'l'   'm'   'n'   'o'
145    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
146    //'p'   'q'   'r'   's'   't'   'u'   'v'   'w'
147    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
148    //'x'   'y'   'z'   '{'   '|'   '}'   '~'   ''
149    0x90, 0x90, 0x90, 0x97, 0x18, 0x99, 0x1a, 0x1b
150};
151
152 CString CLRX::extractSymName(const char*& string, const char* end,
153           bool localLabelSymName)
154{
155    const char* startString = string;
156    if (string != end)
157    {
158        if(isAlpha(*string) || *string == '_' || *string == '.' || *string == '$')
159            for (string++; string != end && (isAlnum(*string) || *string == '_' ||
160                 *string == '.' || *string == '$') ; string++);
161        else if (localLabelSymName && isDigit(*string)) // local label
162        {
163            for (string++; string!=end && isDigit(*string); string++);
164            // check whether is local forward or backward label
165            string = (string != end && (*string == 'f' || *string == 'b')) ?
166                    string+1 : startString;
167            // if not part of binary number or illegal bin number
168            if (startString != string && (string!=end && (isAlnum(*string))))
169                string = startString;
170        }
171    }
172    return CString(startString, string);
173}
174
175CString CLRX::extractScopedSymName(const char*& string, const char* end,
176           bool localLabelSymName)
177{
178    const char* startString = string;
179    const char* lastString = string;
180    if (localLabelSymName && isDigit(*string)) // local label
181    {
182        for (string++; string!=end && isDigit(*string); string++);
183        // check whether is local forward or backward label
184        string = (string != end && (*string == 'f' || *string == 'b')) ?
185                string+1 : startString;
186        // if not part of binary number or illegal bin number
187        if (startString != string && (string!=end && (isAlnum(*string))))
188            string = startString;
189        return CString(startString, string);
190    }
191    while (string != end)
192    {
193        if (*string==':' && string+1!=end && string[1]==':')
194            string += 2;
195        else if (string != startString) // if not start
196            break;
197        // skip string
198        const char* scopeName = string;
199        if (string != end)
200        {
201            if(isAlpha(*string) || *string == '_' || *string == '.' || *string == '$')
202                for (string++; string != end && (isAlnum(*string) || *string == '_' ||
203                     *string == '.' || *string == '$') ; string++);
204        }
205        if (scopeName==string) // is not scope name
206            break;
207        lastString = string;
208    }
209    return CString(startString, lastString);
210}
211
212// skip spaces, labels and '\@' and \(): move to statement skipping all labels
213void CLRX::skipSpacesAndLabels(const char*& linePtr, const char* end)
214{
215    const char* stmtStart;
216    while (true)
217    {
218        skipSpacesToEnd(linePtr, end);
219        stmtStart = linePtr;
220        // skip labels and macro substitutions
221        while (linePtr!=end && (isAlnum(*linePtr) || *linePtr=='$' || *linePtr=='.' ||
222            *linePtr=='_' || *linePtr=='\\'))
223        {
224            if (*linePtr!='\\')
225                linePtr++;
226            else
227            {
228                /* handle \@ and \() for correct parsing */
229                linePtr++;
230                if (linePtr!=end)
231                {
232                    if (*linePtr=='@')
233                        linePtr++;
234                    else if (*linePtr=='(')
235                    {
236                        linePtr++;
237                        if (linePtr!=end && *linePtr==')')
238                            linePtr++;
239                    }
240                }
241            }
242        }
243        skipSpacesToEnd(linePtr, end);
244        if (linePtr==end || *linePtr!=':')
245            break;
246        linePtr++; // skip ':'
247    }
248    linePtr = stmtStart;
249}
250
251// check whether some garbages at end of line (true if not)
252bool AsmParseUtils::checkGarbagesAtEnd(Assembler& asmr, const char* linePtr)
253{
254    skipSpacesToEnd(linePtr, asmr.line + asmr.lineSize);
255    if (linePtr != asmr.line + asmr.lineSize)
256        ASM_FAIL_BY_ERROR(linePtr, "Garbages at end of line")
257    return true;
258}
259
260// get absolute value (by evaluating expression): all symbols must be resolved at this time
261bool AsmParseUtils::getAbsoluteValueArg(Assembler& asmr, uint64_t& value,
262                      const char*& linePtr, bool requiredExpr)
263{
264    const char* end = asmr.line + asmr.lineSize;
265    skipSpacesToEnd(linePtr, end);
266    const char* exprPlace = linePtr;
267    if (AsmExpression::fastExprEvaluate(asmr, linePtr, value))
268        return true;
269    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
270    if (expr == nullptr)
271        return false;
272    if (expr->isEmpty() && requiredExpr)
273        ASM_FAIL_BY_ERROR(exprPlace, "Expected expression")
274    if (expr->isEmpty()) // do not set if empty expression
275        return true;
276    cxuint sectionId; // for getting
277    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
278        return false;
279    else if (sectionId != ASMSECT_ABS)
280        // if not absolute value
281        ASM_FAIL_BY_ERROR(exprPlace, "Expression must be absolute!")
282    return true;
283}
284
285// get any value (also position in section)
286bool AsmParseUtils::getAnyValueArg(Assembler& asmr, uint64_t& value,
287                   cxuint& sectionId, const char*& linePtr)
288{
289    const char* end = asmr.line + asmr.lineSize;
290    skipSpacesToEnd(linePtr, end);
291    const char* exprPlace = linePtr;
292    if (AsmExpression::fastExprEvaluate(asmr, linePtr, value))
293    {
294        sectionId = ASMSECT_ABS;
295        return true;
296    }
297    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
298    if (expr == nullptr)
299        return false;
300    if (expr->isEmpty())
301        ASM_FAIL_BY_ERROR(exprPlace, "Expected expression")
302    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
303        return false;
304    return true;
305}
306
307/* get jump value - if expression have unresolved symbols, then returns output
308 * target expression to resolve later */
309bool AsmParseUtils::getJumpValueArg(Assembler& asmr, uint64_t& value,
310            std::unique_ptr<AsmExpression>& outTargetExpr, const char*& linePtr)
311{
312    const char* end = asmr.line + asmr.lineSize;
313    skipSpacesToEnd(linePtr, end);
314    const char* exprPlace = linePtr;
315    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, false));
316    if (expr == nullptr)
317        return false;
318    if (expr->isEmpty())
319        ASM_FAIL_BY_ERROR(exprPlace, "Expected expression")
320    if (expr->getSymOccursNum()==0)
321    {
322        cxuint sectionId;
323        AsmTryStatus evalStatus = expr->tryEvaluate(asmr, value, sectionId,
324                            asmr.withSectionDiffs());
325        if (evalStatus == AsmTryStatus::FAILED) // failed evaluation!
326            return false;
327        else if (evalStatus == AsmTryStatus::TRY_LATER)
328        {
329            // store out target expression (some symbols is not resolved)
330            asmr.unevalExpressions.push_back(expr.get());
331            outTargetExpr = std::move(expr);
332            return true;
333        }
334        if (sectionId != asmr.currentSection)
335            // if jump outside current section (.text)
336            ASM_FAIL_BY_ERROR(exprPlace, "Jump over current section!")
337        return true;
338    }
339    else
340    {
341        // store out target expression (some symbols is not resolved)
342        outTargetExpr = std::move(expr);
343        return true;
344    }
345}
346
347// get name of some object - accepts '_', '.' in name
348// skipCommaAtError - skip ',' when error
349bool AsmParseUtils::getNameArg(Assembler& asmr, CString& outStr, const char*& linePtr,
350            const char* objName, bool requiredArg, bool skipCommaAtError)
351{
352    const char* end = asmr.line + asmr.lineSize;
353    outStr.clear();
354    skipSpacesToEnd(linePtr, end);
355    if (linePtr == end)
356    {
357        if (!requiredArg)
358            return true; // succeed
359        ASM_FAIL_BY_ERROR(linePtr, (std::string("Expected ")+objName).c_str())
360    }
361    const char* nameStr = linePtr;
362    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
363    {
364        linePtr++;
365        while (linePtr != end && (isAlnum(*linePtr) ||
366            *linePtr == '_' || *linePtr == '.')) linePtr++;
367    }
368    else
369    {
370        // if is not name
371        if (!requiredArg)
372            return true; // succeed
373        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
374                        " place").c_str());
375        if (!skipCommaAtError)
376            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
377        else // skip comma
378            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
379        return false;
380    }
381    outStr.assign(nameStr, linePtr);
382    return true;
383}
384
385// get name of some object - accepts '_', '.' in name
386// like previous function: but static allocated strings
387bool AsmParseUtils::getNameArg(Assembler& asmr, size_t maxOutStrSize, char* outStr,
388               const char*& linePtr, const char* objName, bool requiredArg,
389               bool ignoreLongerName, bool skipCommaAtError)
390{
391    const char* end = asmr.line + asmr.lineSize;
392    skipSpacesToEnd(linePtr, end);
393    if (linePtr == end)
394    {
395        if (!requiredArg)
396        {
397            outStr[0] = 0;
398            return true; // succeed
399        }
400        ASM_FAIL_BY_ERROR(linePtr, (std::string("Expected ")+objName).c_str())
401    }
402    const char* nameStr = linePtr;
403    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
404    {
405        linePtr++;
406        while (linePtr != end && (isAlnum(*linePtr) ||
407            *linePtr == '_' || *linePtr == '.')) linePtr++;
408    }
409    else
410    {
411        if (!requiredArg)
412        {
413            outStr[0] = 0;
414            return true; // succeed
415        }
416        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
417                " place").c_str());
418       
419        if (!skipCommaAtError)
420            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
421        else
422            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
423        return false;
424    }
425    if (maxOutStrSize-1 < size_t(linePtr-nameStr))
426    {
427        if (ignoreLongerName)
428        {
429            // return empty string
430            outStr[0] = 0; // null-char
431            return true;
432        }
433        ASM_FAIL_BY_ERROR(linePtr, (std::string(objName)+" is too long").c_str())
434    }
435    const size_t outStrSize = std::min(maxOutStrSize-1, size_t(linePtr-nameStr));
436    std::copy(nameStr, nameStr+outStrSize, outStr);
437    outStr[outStrSize] = 0; // null-char
438    return true;
439}
440
441// skip comma (can be not present), return true in haveComma if ',' encountered
442bool AsmParseUtils::skipComma(Assembler& asmr, bool& haveComma, const char*& linePtr,
443                        bool errorWhenNoEnd)
444{
445    const char* end = asmr.line + asmr.lineSize;
446    skipSpacesToEnd(linePtr, end);
447    if (linePtr == end)
448    {
449        haveComma = false;
450        return true;
451    }
452    if (*linePtr != ',')
453    {
454        if (errorWhenNoEnd)
455            ASM_FAIL_BY_ERROR(linePtr, "Expected ',' before argument")
456        else
457        {
458            haveComma = false;
459            return true;
460        }
461    }
462    linePtr++;
463    haveComma = true;
464    return true;
465}
466
467// skip comma (must be), if comma not present then fail
468bool AsmParseUtils::skipRequiredComma(Assembler& asmr, const char*& linePtr)
469{
470    const char* end = asmr.line + asmr.lineSize;
471    skipSpacesToEnd(linePtr, end);
472    if (linePtr == end || *linePtr != ',')
473        ASM_FAIL_BY_ERROR(linePtr, "Expected ',' before argument")
474    linePtr++;
475    return true;
476}
477
478// skip comma, but if fail and some character at place, then skip character
479// skip also spaces after comma
480bool AsmParseUtils::skipCommaForMultipleArgs(Assembler& asmr, const char*& linePtr)
481{
482    const char* end = asmr.line + asmr.lineSize;
483    skipSpacesToEnd(linePtr, end); // spaces before ','
484    if (linePtr == end)
485        return false;
486    if (*linePtr != ',')
487    {
488        linePtr++;
489        ASM_FAIL_BY_ERROR(linePtr-1, "Expected ',' before next value")
490    }
491    else
492        skipCharAndSpacesToEnd(linePtr, end);
493    return true;
494}
495
496// get enumeration (name of specified set), return value of recognized name from table
497// prefix - optional prefix for name
498bool AsmParseUtils::getEnumeration(Assembler& asmr, const char*& linePtr,
499              const char* objName, size_t tableSize,
500              const std::pair<const char*, cxuint>* table, cxuint& value,
501              const char* prefix)
502{
503    const char* end = asmr.line + asmr.lineSize;
504    char name[72];
505    skipSpacesToEnd(linePtr, end);
506    const char* namePlace = linePtr;
507    // first, get name
508    if (getNameArg(asmr, 72, name, linePtr, objName))
509    {
510        toLowerString(name);
511        size_t namePos = 0;
512        if (prefix!=nullptr)
513        {
514            size_t psize = ::strlen(prefix);
515            namePos = ::memcmp(name, prefix, psize)==0 ? psize : 0;
516        }
517        cxuint index = binaryMapFind(table, table + tableSize, name+namePos, CStringLess())
518                        - table;
519        if (index != tableSize)
520            value = table[index].second;
521        else // end of this map
522            ASM_FAIL_BY_ERROR(namePlace, (std::string("Unknown ")+objName).c_str())
523        return true;
524    }
525    return false;
526}
527
528// used by asm format pseudo op: '.dim' to parse dimensions (xyz)
529bool AsmParseUtils::parseDimensions(Assembler& asmr, const char*& linePtr, cxuint& dimMask)
530{
531    const char* end = asmr.line + asmr.lineSize;
532    skipSpacesToEnd(linePtr, end);
533    const char* dimPlace = linePtr;
534    char buf[10];
535    dimMask = 0;
536    // get name and try to parse dimension
537    if (getNameArg(asmr, 10, buf, linePtr, "dimension set", false))
538    {
539        toLowerString(buf);
540        for (cxuint i = 0; buf[i]!=0; i++)
541            if (buf[i]=='x')
542                dimMask |= 1;
543            else if (buf[i]=='y')
544                dimMask |= 2;
545            else if (buf[i]=='z')
546                dimMask |= 4;
547            else
548                ASM_FAIL_BY_ERROR(dimPlace, "Unknown dimension type")
549    }
550    else // error
551        return false;
552    return true;
553}
554
555void AsmParseUtils::setSymbolValue(Assembler& asmr, const char* linePtr,
556                    uint64_t value, cxuint sectionId)
557{
558    const char* end = asmr.line + asmr.lineSize;
559    skipSpacesToEnd(linePtr, end);
560   
561    const char* symNamePlace = linePtr;
562    const CString symName = extractScopedSymName(linePtr, end, false);
563    if (symName.empty())
564        ASM_RETURN_BY_ERROR(symNamePlace, "Illegal symbol name")
565    size_t symNameLength = symName.size();
566    // special case for '.' symbol (check whether is in global scope)
567    if (symNameLength >= 3 && symName.compare(symNameLength-3, 3, "::.")==0)
568        ASM_RETURN_BY_ERROR(symNamePlace, "Symbol '.' can be only in global scope")
569    if (!checkGarbagesAtEnd(asmr, linePtr))
570        return;
571   
572    std::pair<AsmSymbolEntry*, bool> res = asmr.insertSymbolInScope(symName,
573                AsmSymbol(sectionId, value));
574    if (!res.second)
575    {
576        // if symbol found
577        if (res.first->second.onceDefined && res.first->second.isDefined()) // if label
578            asmr.printError(symNamePlace, (std::string("Symbol '")+symName.c_str()+
579                        "' is already defined").c_str());
580        else // set value of symbol
581            asmr.setSymbol(*res.first, value, sectionId);
582    }
583    else // set hasValue (by isResolvableSection
584        res.first->second.hasValue = asmr.isResolvableSection(sectionId);
585}
586
587
588ISAAssembler::ISAAssembler(Assembler& _assembler) : assembler(_assembler)
589{ }
590
591ISAAssembler::~ISAAssembler()
592{ }
593
594void AsmSymbol::removeOccurrenceInExpr(AsmExpression* expr, size_t argIndex,
595               size_t opIndex)
596{
597    auto it = std::remove(occurrencesInExprs.begin(), occurrencesInExprs.end(),
598            AsmExprSymbolOccurrence{expr, argIndex, opIndex});
599    occurrencesInExprs.resize(it-occurrencesInExprs.begin());
600}
601
602void AsmSymbol::clearOccurrencesInExpr()
603{
604    /* iteration with index and occurrencesInExprs.size() is required for checking size
605     * after expression deletion that removes occurrences in exprs in this symbol */
606    for (size_t i = 0; i < occurrencesInExprs.size(); i++)
607    {
608        auto& occur = occurrencesInExprs[i];
609        if (occur.expression!=nullptr && !occur.expression->unrefSymOccursNum())
610        {
611            // delete and move back iteration by number of removed elements
612            const size_t oldSize = occurrencesInExprs.size();
613            AsmExpression* occurExpr = occur.expression;
614            occur.expression = nullptr;
615            delete occurExpr;
616            // subtract number of removed elements from counter
617            i -= oldSize-occurrencesInExprs.size();
618        }
619    }
620    occurrencesInExprs.clear();
621}
622
623void AsmSymbol::undefine()
624{
625    hasValue = false;
626    base = false;
627    if (!regRange)
628    {
629        // delete expresion if symbol is not regrange
630        delete expression;
631        expression = nullptr;
632    }
633    value = 0;
634    onceDefined = false;
635}
636
637AsmScope::~AsmScope()
638{
639    for (const auto& entry: scopeMap)
640        delete entry.second;
641    /// remove expressions before symbol map deletion
642    for (auto& entry: symbolMap)
643        entry.second.clearOccurrencesInExpr();
644}
645
646// simple way to delete symbols recursively from scope
647void AsmScope::deleteSymbolsRecursively()
648{
649    symbolMap.clear();
650    for (auto& entry: scopeMap)
651        entry.second->deleteSymbolsRecursively();
652}
653
654void AsmScope::startUsingScope(AsmScope* scope)
655{
656    // do add this
657    auto res = usedScopesSet.insert({scope, usedScopes.end()});
658    usedScopes.push_front(scope);
659    if (!res.second)
660        usedScopes.erase(res.first->second);
661    res.first->second = usedScopes.begin();
662}
663
664void AsmScope::stopUsingScope(AsmScope* scope)
665{
666    auto it = usedScopesSet.find(scope);
667    if (it != usedScopesSet.end()) // do erase from list
668    {
669        usedScopes.erase(it->second);
670        usedScopesSet.erase(it);
671    }
672}
673
674/*
675 * Assembler
676 */
677
678Assembler::Assembler(const CString& filename, std::istream& input, Flags _flags,
679        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
680        std::ostream& _printStream)
681        : format(_format),
682          deviceType(_deviceType),
683          driverVersion(0), llvmVersion(0),
684          _64bit(false),
685          isaAssembler(nullptr),
686          // initialize global scope: adds '.' to symbols
687          globalScope({nullptr,{std::make_pair(".", AsmSymbol(0, uint64_t(0)))}}),
688          currentScope(&globalScope),
689          flags(_flags), 
690          lineSize(0), line(nullptr),
691          endOfAssembly(false),
692          messageStream(msgStream),
693          printStream(_printStream),
694          // value reference and section reference from first symbol: '.'
695          currentSection(globalScope.symbolMap.begin()->second.sectionId),
696          currentOutPos(globalScope.symbolMap.begin()->second.value)
697{
698    filenameIndex = 0;
699    alternateMacro = (flags & ASM_ALTMACRO)!=0;
700    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
701    macroCase = (flags & ASM_MACRONOCASE)==0;
702    oldModParam = (flags & ASM_OLDMODPARAM)!=0;
703    localCount = macroCount = inclusionLevel = 0;
704    macroSubstLevel = repetitionLevel = 0;
705    lineAlreadyRead = false;
706    good = true;
707    resolvingRelocs = false;
708    formatHandler = nullptr;
709    input.exceptions(std::ios::badbit);
710    std::unique_ptr<AsmInputFilter> thatInputFilter(
711                    new AsmStreamInputFilter(input, filename));
712    asmInputFilters.push(thatInputFilter.get());
713    currentInputFilter = thatInputFilter.release();
714}
715
716Assembler::Assembler(const Array<CString>& _filenames, Flags _flags,
717        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
718        std::ostream& _printStream)
719        : format(_format),
720          deviceType(_deviceType),
721          driverVersion(0), llvmVersion(0),
722          _64bit(false),
723          isaAssembler(nullptr),
724          // initialize global scope: adds '.' to symbols
725          globalScope({nullptr,{std::make_pair(".", AsmSymbol(0, uint64_t(0)))}}),
726          currentScope(&globalScope),
727          flags(_flags), 
728          lineSize(0), line(nullptr),
729          endOfAssembly(false),
730          messageStream(msgStream),
731          printStream(_printStream),
732          // value reference and section reference from first symbol: '.'
733          currentSection(globalScope.symbolMap.begin()->second.sectionId),
734          currentOutPos(globalScope.symbolMap.begin()->second.value)
735{
736    filenameIndex = 0;
737    filenames = _filenames;
738    alternateMacro = (flags & ASM_ALTMACRO)!=0;
739    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
740    macroCase = (flags & ASM_MACRONOCASE)==0;
741    oldModParam = (flags & ASM_OLDMODPARAM)!=0;
742    localCount = macroCount = inclusionLevel = 0;
743    macroSubstLevel = repetitionLevel = 0;
744    lineAlreadyRead = false;
745    good = true;
746    resolvingRelocs = false;
747    formatHandler = nullptr;
748    std::unique_ptr<AsmInputFilter> thatInputFilter(
749                new AsmStreamInputFilter(filenames[filenameIndex++]));
750    asmInputFilters.push(thatInputFilter.get());
751    currentInputFilter = thatInputFilter.release();
752}
753
754Assembler::~Assembler()
755{
756    delete formatHandler;
757    if (isaAssembler != nullptr)
758        delete isaAssembler;
759    while (!asmInputFilters.empty())
760    {
761        delete asmInputFilters.top();
762        asmInputFilters.pop();
763    }
764   
765    /// remove expressions before symbol map deletion
766    for (auto& entry: globalScope.symbolMap)
767        entry.second.clearOccurrencesInExpr();
768    for (const auto& entry: globalScope.scopeMap)
769        delete entry.second;
770    for (AsmScope* entry: abandonedScopes)
771        delete entry;
772    globalScope.scopeMap.clear();
773    /// remove expressions before symbol snapshots
774    for (auto& entry: symbolSnapshots)
775        entry->second.clearOccurrencesInExpr();
776   
777    for (auto& entry: symbolSnapshots)
778        delete entry;
779   
780    for (auto& expr: unevalExpressions)
781        delete expr;
782}
783
784// routine to parse string in assembly syntax
785bool Assembler::parseString(std::string& strarray, const char*& linePtr)
786{
787    const char* end = line+lineSize;
788    const char* startPlace = linePtr;
789    skipSpacesToEnd(linePtr, end);
790    strarray.clear();
791    if (linePtr == end || *linePtr != '"')
792    {
793        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
794        THIS_FAIL_BY_ERROR(startPlace, "Expected string")
795    }
796    linePtr++;
797   
798    // main loop, where is character parsing
799    while (linePtr != end && *linePtr != '"')
800    {
801        if (*linePtr == '\\')
802        {
803            // escape
804            linePtr++;
805            uint16_t value;
806            if (linePtr == end)
807                THIS_FAIL_BY_ERROR(startPlace, "Unterminated character of string")
808            if (*linePtr == 'x')
809            {
810                // hex literal
811                const char* charPlace = linePtr-1;
812                linePtr++;
813                if (linePtr == end)
814                    THIS_FAIL_BY_ERROR(startPlace, "Unterminated character of string")
815                value = 0;
816                if (isXDigit(*linePtr))
817                    for (; linePtr != end; linePtr++)
818                    {
819                        cxuint digit;
820                        if (*linePtr >= '0' && *linePtr <= '9')
821                            digit = *linePtr-'0';
822                        else if (*linePtr >= 'a' && *linePtr <= 'f')
823                            digit = *linePtr-'a'+10;
824                        else if (*linePtr >= 'A' && *linePtr <= 'F')
825                            digit = *linePtr-'A'+10;
826                        else
827                            break;
828                        value = (value<<4) + digit;
829                    }
830                else
831                    THIS_FAIL_BY_ERROR(charPlace, "Expected hexadecimal character code")
832                value &= 0xff;
833            }
834            else if (isODigit(*linePtr))
835            {
836                // octal literal
837                value = 0;
838                const char* charPlace = linePtr-1;
839                for (cxuint i = 0; linePtr != end && i < 3; i++, linePtr++)
840                {
841                    if (!isODigit(*linePtr))
842                        break;
843                    value = (value<<3) + uint64_t(*linePtr-'0');
844                    // checking range
845                    if (value > 255)
846                        THIS_FAIL_BY_ERROR(charPlace, "Octal code out of range")
847                }
848            }
849            else
850            {
851                // normal escapes
852                const char c = *linePtr++;
853                switch (c)
854                {
855                    case 'a':
856                        value = '\a';
857                        break;
858                    case 'b':
859                        value = '\b';
860                        break;
861                    case 'r':
862                        value = '\r';
863                        break;
864                    case 'n':
865                        value = '\n';
866                        break;
867                    case 'f':
868                        value = '\f';
869                        break;
870                    case 'v':
871                        value = '\v';
872                        break;
873                    case 't':
874                        value = '\t';
875                        break;
876                    case '\\':
877                        value = '\\';
878                        break;
879                    case '\'':
880                        value = '\'';
881                        break;
882                    case '\"':
883                        value = '\"';
884                        break;
885                    default:
886                        value = c;
887                }
888            }
889            strarray.push_back(value);
890        }
891        else // regular character
892            strarray.push_back(*linePtr++);
893    }
894    if (linePtr == end)
895        THIS_FAIL_BY_ERROR(startPlace, "Unterminated string")
896    linePtr++;
897    return true;
898}
899
900// routine to parse single character literal
901bool Assembler::parseLiteral(uint64_t& value, const char*& linePtr)
902{
903    const char* startPlace = linePtr;
904    const char* end = line+lineSize;
905    // if literal begins '
906    if (linePtr != end && *linePtr == '\'')
907    {
908        linePtr++;
909        if (linePtr == end)
910            THIS_FAIL_BY_ERROR(startPlace, "Unterminated character literal")
911        if (*linePtr == '\'')
912            THIS_FAIL_BY_ERROR(startPlace, "Empty character literal")
913       
914        if (*linePtr != '\\')
915        {
916            value = *linePtr++;
917            if (linePtr == end || *linePtr != '\'')
918                THIS_FAIL_BY_ERROR(startPlace, "Missing ''' at end of literal")
919            linePtr++;
920            return true;
921        }
922        else // escapes
923        {
924            linePtr++;
925            if (linePtr == end)
926                THIS_FAIL_BY_ERROR(startPlace, "Unterminated character literal")
927            if (*linePtr == 'x')
928            {
929                // hex literal
930                linePtr++;
931                if (linePtr == end)
932                    THIS_FAIL_BY_ERROR(startPlace, "Unterminated character literal")
933                value = 0;
934                if (isXDigit(*linePtr))
935                    for (; linePtr != end; linePtr++)
936                    {
937                        cxuint digit;
938                        if (*linePtr >= '0' && *linePtr <= '9')
939                            digit = *linePtr-'0';
940                        else if (*linePtr >= 'a' && *linePtr <= 'f')
941                            digit = *linePtr-'a'+10;
942                        else if (*linePtr >= 'A' && *linePtr <= 'F')
943                            digit = *linePtr-'A'+10;
944                        else
945                            break; // end of literal
946                        value = (value<<4) + digit;
947                    }
948                else
949                    THIS_FAIL_BY_ERROR(startPlace, "Expected hexadecimal character code")
950                value &= 0xff;
951            }
952            else if (isODigit(*linePtr))
953            {
954                // octal literal
955                value = 0;
956                for (cxuint i = 0; linePtr != end && i < 3 && *linePtr != '\'';
957                     i++, linePtr++)
958                {
959                    if (!isODigit(*linePtr))
960                        THIS_FAIL_BY_ERROR(startPlace, "Expected octal character code")
961                    value = (value<<3) + uint64_t(*linePtr-'0');
962                    // checking range
963                    if (value > 255)
964                        THIS_FAIL_BY_ERROR(startPlace, "Octal code out of range")
965                }
966            }
967            else
968            {
969                // normal escapes
970                const char c = *linePtr++;
971                switch (c)
972                {
973                    case 'a':
974                        value = '\a';
975                        break;
976                    case 'b':
977                        value = '\b';
978                        break;
979                    case 'r':
980                        value = '\r';
981                        break;
982                    case 'n':
983                        value = '\n';
984                        break;
985                    case 'f':
986                        value = '\f';
987                        break;
988                    case 'v':
989                        value = '\v';
990                        break;
991                    case 't':
992                        value = '\t';
993                        break;
994                    case '\\':
995                        value = '\\';
996                        break;
997                    case '\'':
998                        value = '\'';
999                        break;
1000                    case '\"':
1001                        value = '\"';
1002                        break;
1003                    default:
1004                        value = c;
1005                }
1006            }
1007            if (linePtr == end || *linePtr != '\'')
1008                THIS_FAIL_BY_ERROR(startPlace, "Missing ''' at end of literal")
1009            linePtr++;
1010            return true;
1011        }
1012    }
1013    // try to parse integer value
1014    try
1015    { value = cstrtovCStyle<uint64_t>(startPlace, line+lineSize, linePtr); }
1016    catch(const ParseException& ex)
1017    {
1018        printError(startPlace, ex.what());
1019        return false;
1020    }
1021    return true;
1022}
1023
1024bool Assembler::parseLiteralNoError(uint64_t& value, const char*& linePtr)
1025{
1026    const char* startPlace = linePtr;
1027    const char* end = line+lineSize;
1028    // if literal begins '
1029    if (linePtr != end && *linePtr == '\'')
1030    {
1031        linePtr++;
1032        if (linePtr == end || *linePtr == '\'')
1033            return false;
1034       
1035        if (*linePtr != '\\')
1036        {
1037            value = *linePtr++;
1038            if (linePtr == end || *linePtr != '\'')
1039                return false;
1040            linePtr++;
1041            return true;
1042        }
1043        else // escapes
1044        {
1045            linePtr++;
1046            if (linePtr == end)
1047                return false;
1048            if (*linePtr == 'x')
1049            {
1050                // hex literal
1051                linePtr++;
1052                if (linePtr == end)
1053                    return false;
1054                value = 0;
1055                if (isXDigit(*linePtr))
1056                    for (; linePtr != end; linePtr++)
1057                    {
1058                        cxuint digit;
1059                        if (*linePtr >= '0' && *linePtr <= '9')
1060                            digit = *linePtr-'0';
1061                        else if (*linePtr >= 'a' && *linePtr <= 'f')
1062                            digit = *linePtr-'a'+10;
1063                        else if (*linePtr >= 'A' && *linePtr <= 'F')
1064                            digit = *linePtr-'A'+10;
1065                        else
1066                            break; // end of literal
1067                        value = (value<<4) + digit;
1068                    }
1069                else
1070                    return false;
1071                value &= 0xff;
1072            }
1073            else if (isODigit(*linePtr))
1074            {
1075                // octal literal
1076                value = 0;
1077                for (cxuint i = 0; linePtr != end && i < 3 && *linePtr != '\'';
1078                     i++, linePtr++)
1079                {
1080                    if (!isODigit(*linePtr))
1081                        return false;
1082                    value = (value<<3) + uint64_t(*linePtr-'0');
1083                    // checking range
1084                    if (value > 255)
1085                        return false;
1086                }
1087            }
1088            else
1089            {
1090                // normal escapes
1091                const char c = *linePtr++;
1092                switch (c)
1093                {
1094                    case 'a':
1095                        value = '\a';
1096                        break;
1097                    case 'b':
1098                        value = '\b';
1099                        break;
1100                    case 'r':
1101                        value = '\r';
1102                        break;
1103                    case 'n':
1104                        value = '\n';
1105                        break;
1106                    case 'f':
1107                        value = '\f';
1108                        break;
1109                    case 'v':
1110                        value = '\v';
1111                        break;
1112                    case 't':
1113                        value = '\t';
1114                        break;
1115                    case '\\':
1116                        value = '\\';
1117                        break;
1118                    case '\'':
1119                        value = '\'';
1120                        break;
1121                    case '\"':
1122                        value = '\"';
1123                        break;
1124                    default:
1125                        value = c;
1126                }
1127            }
1128            if (linePtr == end || *linePtr != '\'')
1129                return false;
1130            linePtr++;
1131            return true;
1132        }
1133    }
1134    // try to parse integer value
1135    try
1136    { value = cstrtovCStyle<uint64_t>(startPlace, line+lineSize, linePtr); }
1137    catch(const ParseException& ex)
1138    { return false; }
1139    return true;
1140}
1141
1142// parse symbol. return PARSED - when successfuly parsed symbol,
1143// MISSING - when no symbol in this place, FAILED - when failed
1144// routine try to create new unresolved symbol if not defined and if dontCreateSymbol=false
1145Assembler::ParseState Assembler::parseSymbol(const char*& linePtr,
1146                AsmSymbolEntry*& entry, bool localLabel, bool dontCreateSymbol)
1147{
1148    const char* startPlace = linePtr;
1149    const CString symName = extractScopedSymName(linePtr, line+lineSize, localLabel);
1150    if (symName.empty())
1151    {
1152        // this is not symbol or a missing symbol
1153        while (linePtr != line+lineSize && !isSpace(*linePtr) && *linePtr != ',')
1154            linePtr++;
1155        entry = nullptr;
1156        return Assembler::ParseState::MISSING;
1157    }
1158    if (symName == ".") // any usage of '.' causes format initialization
1159    {
1160        // special case ('.' - always global)
1161        initializeOutputFormat();
1162        entry = &*globalScope.symbolMap.find(".");
1163        return Assembler::ParseState::PARSED;
1164    }
1165   
1166    Assembler::ParseState state = Assembler::ParseState::PARSED;
1167    bool symHasValue;
1168    if (!isDigit(symName.front()))
1169    {
1170        // regular symbol name (not local label)
1171        AsmScope* outScope;
1172        CString sameSymName;
1173        entry = findSymbolInScope(symName, outScope, sameSymName);
1174        if (sameSymName == ".")
1175        {
1176            // illegal name of symbol (must be in global)
1177            printError(startPlace, "Symbol '.' can be only in global scope");
1178            return Assembler::ParseState::FAILED;
1179        }
1180        if (!dontCreateSymbol && entry==nullptr)
1181        {
1182            // create unresolved symbol if not found
1183            std::pair<AsmSymbolMap::iterator, bool> res =
1184                    outScope->symbolMap.insert(std::make_pair(sameSymName, AsmSymbol()));
1185            entry = &*res.first;
1186            symHasValue = res.first->second.hasValue;
1187        }
1188        else // only find symbol and set isDefined and entry
1189            symHasValue = (entry != nullptr && entry->second.hasValue);
1190    }
1191    else
1192    {
1193        // local labels is in global scope
1194        if (!dontCreateSymbol)
1195        {
1196            // create symbol if not found
1197            std::pair<AsmSymbolMap::iterator, bool> res =
1198                    globalScope.symbolMap.insert(std::make_pair(symName, AsmSymbol()));
1199            entry = &*res.first;
1200            symHasValue = res.first->second.hasValue;
1201        }
1202        else
1203        {
1204            // only find symbol and set isDefined and entry
1205            AsmSymbolMap::iterator it = globalScope.symbolMap.find(symName);
1206            entry = (it != globalScope.symbolMap.end()) ? &*it : nullptr;
1207            symHasValue = (it != globalScope.symbolMap.end() && it->second.hasValue);
1208        }
1209    }
1210   
1211    if (isDigit(symName.front()) && symName[linePtr-startPlace-1] == 'b' && !symHasValue)
1212    {
1213        // failed at finding
1214        std::string error = "Undefined previous local label '";
1215        error.append(symName.begin(), linePtr-startPlace);
1216        error += "'";
1217        printError(startPlace, error.c_str());
1218        state = Assembler::ParseState::FAILED;
1219    }
1220   
1221    return state;
1222}
1223
1224// parse argument's value
1225bool Assembler::parseMacroArgValue(const char*& string, std::string& outStr)
1226{
1227    const char* end = line+lineSize;
1228    bool firstNonSpace = false;
1229    cxbyte prevTok = 0;
1230    cxuint backslash = 0;
1231   
1232    if ((alternateMacro && string != end && *string=='%') ||
1233        (!alternateMacro && string+2 <= end && *string=='\\' && string[1]=='%'))
1234    {
1235        // alternate syntax, parse expression evaluation
1236        // too in \% form
1237        const char* exprPlace = string + ((alternateMacro) ? 1 : 2);
1238        uint64_t value;
1239        if (AsmParseUtils::getAbsoluteValueArg(*this, value, exprPlace, true))
1240        {
1241            char buf[32];
1242            itocstrCStyle<int64_t>(value, buf, 32);
1243            string = exprPlace;
1244            outStr = buf;
1245            return true;
1246        }
1247        else
1248        {
1249            /* if error */
1250            string = exprPlace;
1251            return false;
1252        }
1253    }
1254   
1255    if (alternateMacro && string != end && (*string=='<' || *string=='\'' || *string=='"'))
1256    {
1257        /* alternate string quoting */
1258        const char termChar = (*string=='<') ? '>' : *string;
1259        string++;
1260        bool escape = false;
1261        while (string != end && (*string != termChar || escape))
1262        {
1263            if (!escape && *string=='!')
1264            {
1265                /* skip this escaping */
1266                escape = true;
1267                string++;
1268            }
1269            else
1270            {
1271                /* put character */
1272                escape = false;
1273                outStr.push_back(*string++);
1274            }
1275        }
1276        if (string == end) /* if unterminated string */
1277            THIS_FAIL_BY_ERROR(string, "Unterminated quoted string")
1278        string++;
1279        return true;
1280    }
1281    else if (string != end && *string=='"')
1282    {
1283        // if arg begins from '"'. quoting in old mode
1284        string++;
1285        while (string != end && (*string != '\"' || (backslash&1)!=0))
1286        {
1287            if (*string=='\\')
1288                backslash++;
1289            else
1290                backslash = 0;
1291            outStr.push_back(*string++);
1292        }
1293        if (string == end)
1294            THIS_FAIL_BY_ERROR(string, "Unterminated quoted string")
1295        string++;
1296        return true;
1297    }
1298   
1299    // argument begins from other character
1300    for (; string != end && *string != ','; string++)
1301    {
1302        if(*string == '"') // quoted
1303            return true; // next argument
1304        if (!isSpace(*string))
1305        {
1306            const cxbyte thisTok = (cxbyte(*string) >= 0x20 && cxbyte(*string) < 0x80) ?
1307                tokenCharTable[*string-0x20] : 0;
1308            bool prevTokCont = (prevTok&0x80)!=0;
1309            bool thisTokCont = (thisTok&0x80)!=0;
1310            if (firstNonSpace && ((prevTok!=thisTok && !(thisTokCont ^ prevTokCont)) || 
1311                (prevTok==thisTok && (thisTokCont&prevTokCont))))
1312                break;  // end of token list for macro arg
1313            outStr.push_back(*string);
1314            firstNonSpace = false;
1315            prevTok = thisTok;
1316        }
1317        else
1318        {
1319            firstNonSpace = true;
1320            continue; // space
1321        }
1322    }
1323    return true;
1324}
1325
1326bool Assembler::resolveExprTarget(const AsmExpression* expr,
1327                        uint64_t value, cxuint sectionId)
1328{
1329    const AsmExprTarget& target = expr->getTarget();
1330    switch(target.type)
1331    {
1332        case ASMXTGT_SYMBOL:
1333            // resolve symbol
1334            return setSymbol(*target.symbol, value, sectionId);
1335        case ASMXTGT_DATA8:
1336            if (sectionId != ASMSECT_ABS)
1337                THIS_FAIL_BY_ERROR(expr->getSourcePos(),
1338                        "Relative value is illegal in data expressions")
1339            else
1340            {
1341                printWarningForRange(8, value, expr->getSourcePos());
1342                sections[target.sectionId].content[target.offset] = cxbyte(value);
1343            }
1344            break;
1345        case ASMXTGT_DATA16:
1346            if (sectionId != ASMSECT_ABS)
1347                THIS_FAIL_BY_ERROR(expr->getSourcePos(),
1348                        "Relative value is illegal in data expressions")
1349            else
1350            {
1351                printWarningForRange(16, value, expr->getSourcePos());
1352                SULEV(*reinterpret_cast<uint16_t*>(sections[target.sectionId]
1353                        .content.data() + target.offset), uint16_t(value));
1354            }
1355            break;
1356        case ASMXTGT_DATA32:
1357            if (sectionId != ASMSECT_ABS)
1358                THIS_FAIL_BY_ERROR(expr->getSourcePos(),
1359                        "Relative value is illegal in data expressions")
1360            else
1361            {
1362                printWarningForRange(32, value, expr->getSourcePos());
1363                SULEV(*reinterpret_cast<uint32_t*>(sections[target.sectionId]
1364                        .content.data() + target.offset), uint32_t(value));
1365            }
1366            break;
1367        case ASMXTGT_DATA64:
1368            if (sectionId != ASMSECT_ABS)
1369                THIS_FAIL_BY_ERROR(expr->getSourcePos(),
1370                        "Relative value is illegal in data expressions")
1371            else
1372                SULEV(*reinterpret_cast<uint64_t*>(sections[target.sectionId]
1373                        .content.data() + target.offset), uint64_t(value));
1374            break;
1375        // special case for Code flow
1376        case ASMXTGT_CODEFLOW:
1377            if (target.sectionId != sectionId)
1378                THIS_FAIL_BY_ERROR(expr->getSourcePos(), "Jump over current section!")
1379            else
1380                sections[target.sectionId].codeFlow[target.cflowId].target = value;
1381            break;
1382        default:
1383            // ISA assembler resolves this dependency
1384            if (!isaAssembler->resolveCode(expr->getSourcePos(),
1385                    target.sectionId, sections[target.sectionId].content.data(),
1386                    target.offset, target.type, sectionId, value))
1387                return false;
1388            break;
1389    }
1390    return true;
1391}
1392
1393bool Assembler::setSymbol(AsmSymbolEntry& symEntry, uint64_t value, cxuint sectionId)
1394{
1395    symEntry.second.value = value;
1396    symEntry.second.expression = nullptr;
1397    symEntry.second.sectionId = sectionId;
1398    symEntry.second.hasValue = isResolvableSection(sectionId) || resolvingRelocs;
1399    symEntry.second.regRange = false;
1400    symEntry.second.base = false;
1401    if (!symEntry.second.hasValue) // if not resolved we just return
1402        return true; // no error
1403    bool good = true;
1404   
1405    // resolve value of pending symbols
1406    std::stack<std::pair<AsmSymbolEntry*, size_t> > symbolStack;
1407    symbolStack.push(std::make_pair(&symEntry, 0));
1408    symEntry.second.resolving = true;
1409   
1410    // recursive algorithm in loop form
1411    while (!symbolStack.empty())
1412    {
1413        std::pair<AsmSymbolEntry*, size_t>& entry = symbolStack.top();
1414        if (entry.second < entry.first->second.occurrencesInExprs.size())
1415        {
1416            AsmExprSymbolOccurrence& occurrence =
1417                    entry.first->second.occurrencesInExprs[entry.second];
1418            AsmExpression* expr = occurrence.expression;
1419            expr->substituteOccurrence(occurrence, entry.first->second.value,
1420                       (!isAbsoluteSymbol(entry.first->second)) ?
1421                       entry.first->second.sectionId : ASMSECT_ABS);
1422            entry.second++;
1423           
1424            if (!expr->unrefSymOccursNum())
1425            {
1426                // expresion has been fully resolved
1427                uint64_t value;
1428                cxuint sectionId;
1429                const AsmExprTarget& target = expr->getTarget();
1430                if (!resolvingRelocs || target.type==ASMXTGT_SYMBOL)
1431                {
1432                    // standard mode
1433                    AsmTryStatus evalStatus = expr->tryEvaluate(*this, value, sectionId,
1434                                        withSectionDiffs());
1435                    if (evalStatus == AsmTryStatus::FAILED)
1436                    {
1437                        // if failed
1438                        delete occurrence.expression; // delete expression
1439                        good = false;
1440                        continue;
1441                    }
1442                    else if (evalStatus == AsmTryStatus::TRY_LATER)
1443                    {   // try later if can not be evaluated
1444                        unevalExpressions.push_back(occurrence.expression);
1445                        // but still good
1446                        continue;
1447                    }
1448                }
1449                // resolve expression if at resolving symbol phase
1450                else if (formatHandler==nullptr ||
1451                        !formatHandler->resolveRelocation(expr, value, sectionId))
1452                {
1453                    // if failed
1454                    delete occurrence.expression; // delete expression
1455                    good = false;
1456                    continue;
1457                }
1458               
1459                // resolving
1460                if (target.type == ASMXTGT_SYMBOL)
1461                {    // resolve symbol
1462                    AsmSymbolEntry& curSymEntry = *target.symbol;
1463                    if (!curSymEntry.second.resolving &&
1464                        (!curSymEntry.second.regRange &&
1465                            curSymEntry.second.expression==expr))
1466                    {
1467                        curSymEntry.second.value = value;
1468                        curSymEntry.second.sectionId = sectionId;
1469                        curSymEntry.second.hasValue =
1470                            isResolvableSection(sectionId) || resolvingRelocs;
1471                        symbolStack.push(std::make_pair(&curSymEntry, 0));
1472                        if (!curSymEntry.second.hasValue)
1473                            continue;
1474                        curSymEntry.second.resolving = true;
1475                    }
1476                    // otherwise we ignore circular dependencies
1477                }
1478                else
1479                    good &= resolveExprTarget(expr, value, sectionId);
1480                delete occurrence.expression; // delete expression
1481            }
1482            else // otherwise we only clear occurrence expression
1483                occurrence.expression = nullptr; // clear expression
1484        }
1485        else // pop
1486        {
1487            entry.first->second.resolving = false;
1488            entry.first->second.occurrencesInExprs.clear();
1489            if (entry.first->second.snapshot && --(entry.first->second.refCount) == 0)
1490            {
1491                symbolSnapshots.erase(entry.first);
1492                delete entry.first; // delete this symbol snapshot
1493            }
1494            symbolStack.pop();
1495        }
1496    }
1497    return good;
1498}
1499
1500bool Assembler::assignSymbol(const CString& symbolName, const char* symbolPlace,
1501             const char* linePtr, bool reassign, bool baseExpr)
1502{
1503    skipSpacesToEnd(linePtr, line+lineSize);
1504    size_t symNameLength = symbolName.size();
1505    if (symNameLength >= 3 && symbolName.compare(symNameLength-3, 3, "::.")==0)
1506        THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' can be only in global scope")
1507   
1508    if (linePtr!=line+lineSize && *linePtr=='%')
1509    {
1510        if (symbolName == ".")
1511            THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' requires a resolved expression")
1512        initializeOutputFormat();
1513        ++linePtr;
1514        cxuint regStart, regEnd;
1515        const AsmRegVar* regVar;
1516        if (!isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar))
1517            return false;
1518        skipSpacesToEnd(linePtr, line+lineSize);
1519        if (linePtr != line+lineSize)
1520            THIS_FAIL_BY_ERROR(linePtr, "Garbages at end of expression")
1521       
1522        std::pair<AsmSymbolEntry*, bool> res =
1523                insertSymbolInScope(symbolName, AsmSymbol());
1524        if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1525            res.first->second.isDefined()))
1526        {
1527            // found and can be only once defined
1528            printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1529                        "' is already defined").c_str());
1530            return false;
1531        }
1532        if (!res.first->second.occurrencesInExprs.empty())
1533        {
1534            // regrange found in expressions (error)
1535            std::vector<std::pair<const AsmExpression*, size_t> > exprs;
1536            size_t i = 0;
1537            for (AsmExprSymbolOccurrence occur: res.first->second.occurrencesInExprs)
1538                exprs.push_back(std::make_pair(occur.expression, i++));
1539            // remove duplicates
1540            // sort by value
1541            std::sort(exprs.begin(), exprs.end(),
1542                      [](const std::pair<const AsmExpression*, size_t>& a,
1543                         const std::pair<const AsmExpression*, size_t>& b)
1544                    {
1545                        if (a.first==b.first)
1546                            return a.second<b.second;
1547                        return a.first<b.first;
1548                    });
1549            // make unique and resize (remove duplicates
1550            exprs.resize(std::unique(exprs.begin(), exprs.end(),
1551                       [](const std::pair<const AsmExpression*, size_t>& a,
1552                         const std::pair<const AsmExpression*, size_t>& b)
1553                       { return a.first==b.first; })-exprs.begin());
1554            // sort by occurrence
1555            std::sort(exprs.begin(), exprs.end(),
1556                      [](const std::pair<const AsmExpression*, size_t>& a,
1557                         const std::pair<const AsmExpression*, size_t>& b)
1558                    { return a.second<b.second; });
1559            // print errors (in order without duplicates)
1560            for (std::pair<const AsmExpression*, size_t> elem: exprs)
1561                printError(elem.first->getSourcePos(), "Expression have register symbol");
1562           
1563            printError(symbolPlace, (std::string("Register range symbol '") +
1564                            symbolName.c_str() + "' was used in some expressions").c_str());
1565            return false;
1566        }
1567        // setup symbol entry (required)
1568        AsmSymbolEntry& symEntry = *res.first;
1569        symEntry.second.expression = nullptr;
1570        symEntry.second.regVar = regVar;
1571        symEntry.second.onceDefined = !reassign;
1572        symEntry.second.base = false;
1573        symEntry.second.sectionId = ASMSECT_ABS;
1574        symEntry.second.regRange = symEntry.second.hasValue = true;
1575        symEntry.second.value = (regStart | (uint64_t(regEnd)<<32));
1576        return true;
1577    }
1578   
1579    const char* exprPlace = linePtr;
1580    // make base expr if baseExpr=true and symbolName is not output counter
1581    bool makeBaseExpr = (baseExpr && symbolName != ".");
1582   
1583    std::unique_ptr<AsmExpression> expr;
1584    uint64_t value;
1585    cxuint sectionId = ASMSECT_ABS;
1586    if (makeBaseExpr || !AsmExpression::fastExprEvaluate(*this, linePtr, value))
1587    {
1588        expr.reset(AsmExpression::parse(*this, linePtr, makeBaseExpr));
1589        if (!expr) // no expression, errors
1590            return false;
1591    }
1592   
1593    if (linePtr != line+lineSize)
1594        THIS_FAIL_BY_ERROR(linePtr, "Garbages at end of expression")
1595    if (expr && expr->isEmpty()) // empty expression, we treat as error
1596        THIS_FAIL_BY_ERROR(exprPlace, "Expected assignment expression")
1597   
1598    if (symbolName == ".")
1599    {
1600        // assigning '.'
1601        if (!expr) // if fast path
1602            return assignOutputCounter(symbolPlace, value, sectionId);
1603        if (!expr->evaluate(*this, value, sectionId))
1604            return false;
1605        if (expr->getSymOccursNum()==0)
1606            return assignOutputCounter(symbolPlace, value, sectionId);
1607        else
1608            THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' requires a resolved expression")
1609    }
1610   
1611    std::pair<AsmSymbolEntry*, bool> res = insertSymbolInScope(symbolName, AsmSymbol());
1612    if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1613        res.first->second.isDefined()))
1614    {
1615        // found and can be only once defined
1616        printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1617                    "' is already defined").c_str());
1618        return false;
1619    }
1620    AsmSymbolEntry& symEntry = *res.first;
1621   
1622    bool tryLater = false;
1623    if (!expr)
1624    {
1625        setSymbol(symEntry, value, sectionId);
1626        symEntry.second.onceDefined = !reassign;
1627    }
1628    else if (expr->getSymOccursNum()==0)
1629    {
1630        // can evalute, assign now
1631        uint64_t value;
1632        cxuint sectionId;
1633       
1634        AsmTryStatus evalStatus = expr->tryEvaluate(*this, value, sectionId,
1635                                    withSectionDiffs());
1636        if (evalStatus == AsmTryStatus::FAILED)
1637            return false;
1638        else if (evalStatus == AsmTryStatus::TRY_LATER)
1639            tryLater = true;
1640        else
1641        {   // success
1642            setSymbol(symEntry, value, sectionId);
1643            symEntry.second.onceDefined = !reassign;
1644        }
1645    }
1646    else
1647        tryLater = true;
1648   
1649    if (tryLater) // set expression
1650    {
1651        expr->setTarget(AsmExprTarget::symbolTarget(&symEntry));
1652        if (expr->getSymOccursNum() == 0)
1653            unevalExpressions.push_back(expr.get());
1654        symEntry.second.expression = expr.release();
1655        symEntry.second.regRange = symEntry.second.hasValue = false;
1656        symEntry.second.onceDefined = !reassign;
1657        symEntry.second.base = baseExpr;
1658        if (baseExpr && !symEntry.second.occurrencesInExprs.empty())
1659        {
1660            /* make snapshot now resolving dependencies */
1661            AsmSymbolEntry* tempSymEntry;
1662            if (!AsmExpression::makeSymbolSnapshot(*this, symEntry, tempSymEntry,
1663                    &symEntry.second.occurrencesInExprs[0].expression->getSourcePos()))
1664                return false;
1665            tempSymEntry->second.occurrencesInExprs =
1666                        symEntry.second.occurrencesInExprs;
1667            // clear occurrences after copy
1668            symEntry.second.occurrencesInExprs.clear();
1669            if (tempSymEntry->second.hasValue) // set symbol chain
1670                setSymbol(*tempSymEntry, tempSymEntry->second.value,
1671                          tempSymEntry->second.sectionId);
1672        }
1673    }
1674    return true;
1675}
1676
1677bool Assembler::assignOutputCounter(const char* symbolPlace, uint64_t value,
1678            cxuint sectionId, cxbyte fillValue)
1679{
1680    initializeOutputFormat();
1681    // checking conditions and fail if not satisfied
1682    if (currentSection != sectionId && sectionId != ASMSECT_ABS)
1683        THIS_FAIL_BY_ERROR(symbolPlace, "Illegal section change for symbol '.'")
1684    if (currentSection != ASMSECT_ABS && int64_t(currentOutPos) > int64_t(value))
1685        /* check attempt to move backwards only for section that is not absolute */
1686        THIS_FAIL_BY_ERROR(symbolPlace, "Attempt to move backwards")
1687    if (!isAddressableSection())
1688        THIS_FAIL_BY_ERROR(symbolPlace,
1689                   "Change output counter inside non-addressable section is illegal")
1690    if (currentSection==ASMSECT_ABS && fillValue!=0)
1691        printWarning(symbolPlace, "Fill value is ignored inside absolute section");
1692    if (value-currentOutPos!=0)
1693        reserveData(value-currentOutPos, fillValue);
1694    currentOutPos = value;
1695    return true;
1696}
1697
1698// skip symbol name, return false if not symbol
1699bool Assembler::skipSymbol(const char*& linePtr)
1700{
1701    const char* end = line+lineSize;
1702    skipSpacesToEnd(linePtr, end);
1703    const char* start = linePtr;
1704    if (linePtr != end)
1705    {
1706        /* skip only symbol name */
1707        if(isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.' || *linePtr == '$')
1708            for (linePtr++; linePtr != end && (isAlnum(*linePtr) || *linePtr == '_' ||
1709                 *linePtr == '.' || *linePtr == '$') ; linePtr++);
1710    }
1711    if (start == linePtr)
1712    {
1713        // this is not symbol name
1714        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
1715        printError(start, "Expected symbol name");
1716        return false;
1717    }
1718    return true;
1719}
1720
1721bool Assembler::isAbsoluteSymbol(const AsmSymbol& symbol) const
1722{
1723    if (symbol.sectionId == ASMSECT_ABS)
1724        return true;
1725    // otherwise check section
1726    if (sections.empty())
1727        return false; // fallback
1728    const AsmSection& section = sections[symbol.sectionId];
1729    return (section.flags&ASMSECT_ABS_ADDRESSABLE) != 0;
1730}
1731
1732void Assembler::printWarning(const AsmSourcePos& pos, const char* message)
1733{
1734    if ((flags & ASM_WARNINGS) == 0)
1735        return; // do nothing
1736    pos.print(messageStream);
1737    messageStream.write(": Warning: ", 11);
1738    messageStream.write(message, ::strlen(message));
1739    messageStream.put('\n');
1740}
1741
1742void Assembler::printError(const AsmSourcePos& pos, const char* message)
1743{
1744    good = false;
1745    pos.print(messageStream);
1746    messageStream.write(": Error: ", 9);
1747    messageStream.write(message, ::strlen(message));
1748    messageStream.put('\n');
1749}
1750
1751// special routine to printing warning when value out of range
1752void Assembler::printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
1753        cxbyte signess)
1754{
1755    if (bits < 64)
1756    {
1757        /* signess - WS_BOTH - check value range as signed value
1758         * WS_UNSIGNED - check value as unsigned value */
1759        if (signess == WS_BOTH &&
1760            !(int64_t(value) >= (1LL<<bits) || int64_t(value) < -(1LL<<(bits-1))))
1761            return;
1762        if (signess == WS_UNSIGNED && (value < (1ULL<<bits)))
1763            return;
1764        std::string warning = "Value ";
1765        char buf[32];
1766        itocstrCStyle(value, buf, 32, 16);
1767        warning += buf;
1768        warning += " truncated to ";
1769        itocstrCStyle(value&((1ULL<<bits)-1), buf, 32, 16);
1770        warning += buf;
1771        printWarning(pos, warning.c_str());
1772    }
1773}
1774
1775void Assembler::addIncludeDir(const CString& includeDir)
1776{
1777    includeDirs.push_back(includeDir);
1778}
1779
1780void Assembler::addInitialDefSym(const CString& symName, uint64_t value)
1781{
1782    defSyms.push_back({symName, value});
1783}
1784
1785// push clause to stack ('.ifXXX','macro','rept'), return true if no error
1786// for '.else' changes current clause
1787bool Assembler::pushClause(const char* string, AsmClauseType clauseType, bool satisfied,
1788               bool& included)
1789{
1790    if (clauseType == AsmClauseType::MACRO || clauseType == AsmClauseType::IF ||
1791        clauseType == AsmClauseType::REPEAT)
1792    {
1793        // add new clause
1794        clauses.push({ clauseType, getSourcePos(string), satisfied, { } });
1795        included = satisfied;
1796        return true;
1797    }
1798    if (clauses.empty())
1799    {
1800        // no clauses
1801        if (clauseType == AsmClauseType::ELSEIF)
1802            printError(string, "No '.if' before '.elseif");
1803        else // else
1804            printError(string, "No '.if' before '.else'");
1805        return false;
1806    }
1807    AsmClause& clause = clauses.top();
1808    switch(clause.type)
1809    {
1810        case AsmClauseType::ELSE:
1811            if (clauseType == AsmClauseType::ELSEIF)
1812                printError(string, "'.elseif' after '.else'");
1813            else // else
1814                printError(string, "Duplicate of '.else'");
1815            printError(clause.sourcePos, "here is previous '.else'"); 
1816            printError(clause.prevIfPos, "here is begin of conditional clause"); 
1817            return false;
1818        case AsmClauseType::MACRO:
1819            THIS_FAIL_BY_ERROR(string, clauseType == AsmClauseType::ELSEIF ?
1820                        "No '.if' before '.elseif' inside macro" :
1821                        "No '.if' before '.else' inside macro")
1822        case AsmClauseType::REPEAT:
1823            THIS_FAIL_BY_ERROR(string, clauseType == AsmClauseType::ELSEIF ?
1824                        "No '.if' before '.elseif' inside repetition" :
1825                        "No '.if' before '.else' inside repetition")
1826        default:
1827            break;
1828    }
1829    included = satisfied && !clause.condSatisfied;
1830    clause.condSatisfied |= included;
1831    if (clause.type == AsmClauseType::IF)
1832        clause.prevIfPos = clause.sourcePos;
1833    clause.type = clauseType;
1834    clause.sourcePos = getSourcePos(string);
1835    return true;
1836}
1837
1838// pop clause ('.endif','.endm','.endr') from stack
1839bool Assembler::popClause(const char* string, AsmClauseType clauseType)
1840{
1841    if (clauses.empty())
1842    {
1843        // no clauses
1844        if (clauseType == AsmClauseType::IF)
1845            printError(string, "No conditional before '.endif'");
1846        else if (clauseType == AsmClauseType::MACRO) // macro
1847            printError(string, "No '.macro' before '.endm'");
1848        else if (clauseType == AsmClauseType::REPEAT) // repeat
1849            printError(string, "No '.rept' before '.endr'");
1850        return false;
1851    }
1852    AsmClause& clause = clauses.top();
1853    // when macro, reepats or conditional finished by wrong pseudo-op
1854    // ('.macro' -> '.endif', etc)
1855    switch(clause.type)
1856    {
1857        case AsmClauseType::IF:
1858        case AsmClauseType::ELSE:
1859        case AsmClauseType::ELSEIF:
1860            if (clauseType == AsmClauseType::MACRO)
1861                THIS_FAIL_BY_ERROR(string, "Ending macro across conditionals")
1862            if (clauseType == AsmClauseType::REPEAT)
1863                THIS_FAIL_BY_ERROR(string, "Ending repetition across conditionals")
1864            break;
1865        case AsmClauseType::MACRO:
1866            if (clauseType == AsmClauseType::REPEAT)
1867                THIS_FAIL_BY_ERROR(string, "Ending repetition across macro")
1868            if (clauseType == AsmClauseType::IF)
1869                THIS_FAIL_BY_ERROR(string, "Ending conditional across macro")
1870            break;
1871        case AsmClauseType::REPEAT:
1872            if (clauseType == AsmClauseType::MACRO)
1873                THIS_FAIL_BY_ERROR(string, "Ending macro across repetition")
1874            if (clauseType == AsmClauseType::IF)
1875                THIS_FAIL_BY_ERROR(string, "Ending conditional across repetition")
1876            break;
1877        default:
1878            break;
1879    }
1880    clauses.pop();
1881    return true;
1882}
1883
1884Assembler::ParseState Assembler::makeMacroSubstitution(const char* linePtr)
1885{
1886    const char* end = line+lineSize;
1887    const char* macroStartPlace = linePtr;
1888   
1889    CString macroName = extractSymName(linePtr, end, false);
1890    if (macroName.empty())
1891        return ParseState::MISSING;
1892    if (macroCase)
1893        toLowerString(macroName);
1894    AsmMacroMap::const_iterator it = macroMap.find(macroName);
1895    if (it == macroMap.end())
1896        return ParseState::MISSING; // macro not found
1897   
1898    /* parse arguments */
1899    RefPtr<const AsmMacro> macro = it->second;
1900    const size_t macroArgsNum = macro->getArgsNum();
1901    bool good = true;
1902    AsmMacroInputFilter::MacroArgMap argMap(macroArgsNum);
1903    for (size_t i = 0; i < macroArgsNum; i++) // set name of args
1904        argMap[i].first = macro->getArg(i).name;
1905   
1906    for (size_t i = 0; i < macroArgsNum; i++)
1907    {
1908        const AsmMacroArg& arg = macro->getArg(i);
1909       
1910        skipSpacesToEnd(linePtr, end);
1911        if (linePtr!=end && *linePtr==',' && i!=0)
1912            skipCharAndSpacesToEnd(linePtr, end);
1913       
1914        std::string macroArg;
1915        const char* argPlace = linePtr;
1916        if (!arg.vararg)
1917        {
1918            // regular macro argument
1919            if (!parseMacroArgValue(linePtr, macroArg))
1920            {
1921                good = false;
1922                continue;
1923            }
1924        }
1925        else
1926        {
1927            /* parse variadic arguments, they requires ',' separator */
1928            bool argGood = true;
1929            while (linePtr != end)
1930            {
1931                if (!parseMacroArgValue(linePtr, macroArg))
1932                {
1933                    argGood = good = false;
1934                    break;
1935                }
1936                skipSpacesToEnd(linePtr, end);
1937                if (linePtr!=end)
1938                {
1939                    if(*linePtr==',')
1940                    {
1941                        skipCharAndSpacesToEnd(linePtr, end);
1942                        macroArg.push_back(',');
1943                    }
1944                    else
1945                    {
1946                        printError(linePtr, "Garbages at end of line");
1947                        argGood = good = false;
1948                        break;
1949                    }
1950                }
1951            }
1952            if (!argGood) // not so good
1953                continue;
1954        }
1955        argMap[i].second = macroArg;
1956        if (arg.required && argMap[i].second.empty())
1957        {
1958            // error, value required
1959            printError(argPlace, (std::string("Value required for macro argument '") +
1960                    arg.name.c_str() + '\'').c_str());
1961            good = false;
1962        }
1963        else if (argMap[i].second.empty())
1964            argMap[i].second = arg.defaultValue;
1965    }
1966   
1967    skipSpacesToEnd(linePtr, end);
1968    if (!good)
1969        return ParseState::FAILED;
1970    if (linePtr != end)
1971    {
1972        printError(linePtr, "Garbages at end of line");
1973        return ParseState::FAILED;
1974    }
1975   
1976    // check depth of macro substitution
1977    if (macroSubstLevel == 1000)
1978    {
1979        printError(macroStartPlace, "Macro substitution level is greater than 1000");
1980        return ParseState::FAILED;
1981    }
1982    // sort argmap before using
1983    mapSort(argMap.begin(), argMap.end());
1984    // create macro input filter and push to stack
1985    std::unique_ptr<AsmInputFilter> macroFilter(new AsmMacroInputFilter(macro,
1986            getSourcePos(macroStartPlace), std::move(argMap), macroCount++,
1987            alternateMacro));
1988    asmInputFilters.push(macroFilter.release());
1989    currentInputFilter = asmInputFilters.top();
1990    macroSubstLevel++;
1991    return ParseState::PARSED;
1992}
1993
1994struct ScopeUsingStackElem
1995{
1996    AsmScope* scope;
1997    std::list<AsmScope*>::iterator usingIt;
1998};
1999
2000// routine to find scope in scope (only traversing by '.using's)
2001AsmScope* Assembler::findScopeInScope(AsmScope* scope, const CString& scopeName,
2002                  std::unordered_set<AsmScope*>& scopeSet)
2003{
2004    if (!scopeSet.insert(scope).second)
2005        return nullptr;
2006    std::stack<ScopeUsingStackElem> usingStack;
2007    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2008    while (!usingStack.empty())
2009    {
2010        ScopeUsingStackElem& current = usingStack.top();
2011        AsmScope* curScope = current.scope;
2012        if (current.usingIt == curScope->usedScopes.begin())
2013        {
2014            // first we found in this scope
2015            auto it = curScope->scopeMap.find(scopeName);
2016            if (it != curScope->scopeMap.end())
2017                return it->second;
2018        }
2019        // next we find in used children
2020        if (current.usingIt != curScope->usedScopes.end())
2021        {
2022            AsmScope* child = *current.usingIt;
2023            if (scopeSet.insert(child).second) // we insert, new
2024                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2025            ++current.usingIt; // next
2026        }
2027        else // back
2028            usingStack.pop();
2029    }
2030    return nullptr;
2031}
2032
2033AsmScope* Assembler::getRecurScope(const CString& scopePlace, bool ignoreLast,
2034                    const char** lastStep)
2035{
2036    AsmScope* scope = currentScope;
2037    const char* str = scopePlace.c_str();
2038    if (*str==':' && str[1]==':')
2039    {
2040        // choose global scope
2041        scope = &globalScope;
2042        str += 2;
2043    }
2044   
2045    std::vector<CString> scopeTrack;
2046    const char* lastStepCur = str;
2047    while (*str != 0)
2048    {
2049        const char* scopeNameStr = str;
2050        while (*str!=':' && *str!=0) str++;
2051        if (*str==0 && ignoreLast) // ignore last
2052            break;
2053        scopeTrack.push_back(CString(scopeNameStr, str));
2054        if (*str==':' && str[1]==':')
2055            str += 2;
2056        lastStepCur = str;
2057    }
2058    if (lastStep != nullptr)
2059        *lastStep = lastStepCur;
2060    if (scopeTrack.empty()) // no scope path
2061        return scope;
2062   
2063    std::unordered_set<AsmScope*> scopeSet;
2064    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2065    {  // find this scope
2066        AsmScope* newScope = findScopeInScope(scope2, scopeTrack[0], scopeSet);
2067        if (newScope != nullptr)
2068        {
2069            scope = newScope->parent;
2070            break;
2071        }
2072    }
2073   
2074    // otherwise create in current/global scope
2075    for (const CString& name: scopeTrack)
2076        getScope(scope, name, scope);
2077    return scope;
2078}
2079
2080// internal routine to find symbol in scope (only traversing by '.using's)
2081AsmSymbolEntry* Assembler::findSymbolInScopeInt(AsmScope* scope,
2082                    const CString& symName, std::unordered_set<AsmScope*>& scopeSet)
2083{
2084    if (!scopeSet.insert(scope).second)
2085        return nullptr;
2086    std::stack<ScopeUsingStackElem> usingStack;
2087    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2088    while (!usingStack.empty())
2089    {
2090        ScopeUsingStackElem& current = usingStack.top();
2091        AsmScope* curScope = current.scope;
2092        if (current.usingIt == curScope->usedScopes.begin())
2093        {
2094            // first we found in this scope
2095            AsmSymbolMap::iterator it = curScope->symbolMap.find(symName);
2096            if (it != curScope->symbolMap.end())
2097                return &*it;
2098        }
2099        // next we find in used children
2100        if (current.usingIt != curScope->usedScopes.end())
2101        {
2102            AsmScope* child = *current.usingIt;
2103            if (scopeSet.insert(child).second) // we insert, new
2104                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2105            ++current.usingIt; // next
2106        }
2107        else // back
2108            usingStack.pop();
2109    }
2110    return nullptr;
2111}
2112
2113// real routine to find symbol in scope (traverse by all visible scopes)
2114AsmSymbolEntry* Assembler::findSymbolInScope(const CString& symName, AsmScope*& scope,
2115            CString& sameSymName, bool insertMode)
2116{
2117    const char* lastStep = nullptr;
2118    scope = getRecurScope(symName, true, &lastStep);
2119    std::unordered_set<AsmScope*> scopeSet;
2120    AsmSymbolEntry* foundSym = findSymbolInScopeInt(scope, lastStep, scopeSet);
2121    sameSymName = lastStep;
2122    if (foundSym != nullptr)
2123        return foundSym;
2124    if (lastStep != symName)
2125        return nullptr;
2126    // otherwise is symName is not normal symName
2127    scope = currentScope;
2128    if (insertMode)
2129        return nullptr;
2130   
2131    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2132    {  // find this scope
2133        foundSym = findSymbolInScopeInt(scope2, lastStep, scopeSet);
2134        if (foundSym != nullptr)
2135            return foundSym;
2136    }
2137    return nullptr;
2138}
2139
2140std::pair<AsmSymbolEntry*, bool> Assembler::insertSymbolInScope(const CString& symName,
2141                 const AsmSymbol& symbol)
2142{
2143    AsmScope* outScope;
2144    CString sameSymName;
2145    AsmSymbolEntry* symEntry = findSymbolInScope(symName, outScope, sameSymName, true);
2146    if (symEntry==nullptr)
2147    {
2148        auto res = outScope->symbolMap.insert({ sameSymName, symbol });
2149        return std::make_pair(&*res.first, res.second);
2150    }
2151    return std::make_pair(symEntry, false);
2152}
2153
2154// internal routine to find regvar in scope (only traversing by '.using's)
2155AsmRegVarEntry* Assembler::findRegVarInScopeInt(AsmScope* scope, const CString& rvName,
2156                std::unordered_set<AsmScope*>& scopeSet)
2157{
2158    if (!scopeSet.insert(scope).second)
2159        return nullptr;
2160    std::stack<ScopeUsingStackElem> usingStack;
2161    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2162    while (!usingStack.empty())
2163    {
2164        ScopeUsingStackElem& current = usingStack.top();
2165        AsmScope* curScope = current.scope;
2166        if (current.usingIt == curScope->usedScopes.begin())
2167        {
2168            // first we found in this scope
2169            AsmRegVarMap::iterator it = curScope->regVarMap.find(rvName);
2170            if (it != curScope->regVarMap.end())
2171                return &*it;
2172        }
2173        // next we find in used children
2174        if (current.usingIt != curScope->usedScopes.end())
2175        {
2176            AsmScope* child = *current.usingIt;
2177            if (scopeSet.insert(child).second) // we insert, new
2178                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2179            ++current.usingIt; // next
2180        }
2181        else // back
2182            usingStack.pop();
2183    }
2184    return nullptr;
2185}
2186
2187// real routine to find regvar in scope (traverse by all visible scopes)
2188AsmRegVarEntry* Assembler::findRegVarInScope(const CString& rvName, AsmScope*& scope,
2189                      CString& sameRvName, bool insertMode)
2190{
2191    const char* lastStep = nullptr;
2192    scope = getRecurScope(rvName, true, &lastStep);
2193    std::unordered_set<AsmScope*> scopeSet;
2194    AsmRegVarEntry* foundRv = findRegVarInScopeInt(scope, lastStep, scopeSet);
2195    sameRvName = lastStep;
2196    if (foundRv != nullptr)
2197        return foundRv;
2198    if (lastStep != rvName)
2199        return nullptr;
2200    // otherwise is rvName is not normal rvName
2201    scope = currentScope;
2202    if (insertMode)
2203        return nullptr;
2204   
2205    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2206    {  // find this scope
2207        foundRv = findRegVarInScopeInt(scope2, lastStep, scopeSet);
2208        if (foundRv != nullptr)
2209            return foundRv;
2210    }
2211    return nullptr;
2212}
2213
2214std::pair<AsmRegVarEntry*, bool> Assembler::insertRegVarInScope(const CString& rvName,
2215                 const AsmRegVar& regVar)
2216{
2217    AsmScope* outScope;
2218    CString sameRvName;
2219    AsmRegVarEntry* rvEntry = findRegVarInScope(rvName, outScope, sameRvName, true);
2220    if (rvEntry==nullptr)
2221    {
2222        auto res = outScope->regVarMap.insert({ sameRvName, regVar });
2223        return std::make_pair(&*res.first, res.second);
2224    }
2225    return std::make_pair(rvEntry, false);
2226}
2227
2228bool Assembler::getScope(AsmScope* parent, const CString& scopeName, AsmScope*& scope)
2229{
2230    std::unordered_set<AsmScope*> scopeSet;
2231    AsmScope* foundScope = findScopeInScope(parent, scopeName, scopeSet);
2232    if (foundScope != nullptr)
2233    {
2234        scope = foundScope;
2235        return false;
2236    }
2237    std::unique_ptr<AsmScope> newScope(new AsmScope(parent));
2238    auto res = parent->scopeMap.insert(std::make_pair(scopeName, newScope.get()));
2239    scope = newScope.release();
2240    return res.second;
2241}
2242
2243bool Assembler::pushScope(const CString& scopeName)
2244{
2245    if (scopeName.empty())
2246    {
2247        // temporary scope
2248        std::unique_ptr<AsmScope> newScope(new AsmScope(currentScope, true));
2249        currentScope->scopeMap.insert(std::make_pair("", newScope.get()));
2250        currentScope = newScope.release();
2251    }
2252    else
2253        getScope(currentScope, scopeName, currentScope);
2254    scopeStack.push(currentScope);
2255    return true; // always good even if scope exists
2256}
2257
2258bool Assembler::popScope()
2259{
2260    if (scopeStack.empty())
2261        return false; // can't pop scope
2262    if (currentScope->temporary)
2263    {
2264        // delete scope
2265        currentScope->parent->scopeMap.erase("");
2266        const bool oldResolvingRelocs = resolvingRelocs;
2267        resolvingRelocs = true; // allow to resolve relocations
2268        tryToResolveSymbols(currentScope);
2269        printUnresolvedSymbols(currentScope);
2270        resolvingRelocs = oldResolvingRelocs;
2271        currentScope->deleteSymbolsRecursively();
2272        abandonedScopes.push_back(currentScope);
2273    }
2274    scopeStack.pop();
2275    currentScope = (!scopeStack.empty()) ? scopeStack.top() : &globalScope;
2276    return true;
2277}
2278
2279bool Assembler::includeFile(const char* pseudoOpPlace, const std::string& filename)
2280{
2281    if (inclusionLevel == 500)
2282        THIS_FAIL_BY_ERROR(pseudoOpPlace, "Inclusion level is greater than 500")
2283    std::unique_ptr<AsmInputFilter> newInputFilter(new AsmStreamInputFilter(
2284                getSourcePos(pseudoOpPlace), filename));
2285    asmInputFilters.push(newInputFilter.release());
2286    currentInputFilter = asmInputFilters.top();
2287    inclusionLevel++;
2288    return true;
2289}
2290
2291bool Assembler::readLine()
2292{
2293    line = currentInputFilter->readLine(*this, lineSize);
2294    while (line == nullptr)
2295    {
2296        // no line
2297        if (asmInputFilters.size() > 1)
2298        {
2299            /* decrease some level of a nesting */
2300            if (currentInputFilter->getType() == AsmInputFilterType::MACROSUBST)
2301                macroSubstLevel--;
2302            else if (currentInputFilter->getType() == AsmInputFilterType::STREAM)
2303                inclusionLevel--;
2304            else if (currentInputFilter->getType() == AsmInputFilterType::REPEAT)
2305                repetitionLevel--;
2306            delete asmInputFilters.top();
2307            asmInputFilters.pop();
2308        }
2309        else if (filenameIndex<filenames.size())
2310        {
2311            /* handling input assembler that have many files */
2312            do {
2313                // delete previous filter
2314                delete asmInputFilters.top();
2315                asmInputFilters.pop();
2316                /// create new input filter
2317                std::unique_ptr<AsmStreamInputFilter> thatFilter(
2318                    new AsmStreamInputFilter(filenames[filenameIndex++]));
2319                asmInputFilters.push(thatFilter.get());
2320                currentInputFilter = thatFilter.release();
2321                line = currentInputFilter->readLine(*this, lineSize);
2322            } while (line==nullptr && filenameIndex<filenames.size());
2323           
2324            return (line!=nullptr);
2325        }
2326        else
2327            return false;
2328        currentInputFilter = asmInputFilters.top();
2329        line = currentInputFilter->readLine(*this, lineSize);
2330    }
2331    return true;
2332}
2333
2334// reserve data in current section and fill values (used by '.skip' or position movement)
2335cxbyte* Assembler::reserveData(size_t size, cxbyte fillValue)
2336{
2337    if (currentSection != ASMSECT_ABS)
2338    {
2339        size_t oldOutPos = currentOutPos;
2340        AsmSection& section = sections[currentSection];
2341        if ((section.flags & ASMSECT_WRITEABLE) == 0)
2342        {
2343             // non writeable, only change output position (do not fill)
2344            currentOutPos += size;
2345            section.size += size;
2346            return nullptr;
2347        }
2348        else
2349        {
2350            section.content.insert(section.content.end(), size, fillValue);
2351            currentOutPos += size;
2352            return section.content.data() + oldOutPos;
2353        }
2354    }
2355    else
2356    {
2357        currentOutPos += size;
2358        return nullptr;
2359    }
2360}
2361
2362
2363void Assembler::goToMain(const char* pseudoOpPlace)
2364{
2365    try
2366    { formatHandler->setCurrentKernel(ASMKERN_GLOBAL); }
2367    catch(const AsmFormatException& ex) // if error
2368    { printError(pseudoOpPlace, ex.what()); }
2369   
2370    currentOutPos = sections[currentSection].getSize();
2371}
2372
2373void Assembler::goToKernel(const char* pseudoOpPlace, const char* kernelName)
2374{
2375    auto kmit = kernelMap.find(kernelName);
2376    if (kmit == kernelMap.end())
2377    {
2378        // not found, add new kernel
2379        cxuint kernelId;
2380        try
2381        { kernelId = formatHandler->addKernel(kernelName); }
2382        catch(const AsmFormatException& ex)
2383        {
2384            // error!
2385            printError(pseudoOpPlace, ex.what());
2386            return;
2387        }
2388        // add new kernel entries and section entry
2389        auto it = kernelMap.insert(std::make_pair(kernelName, kernelId)).first;
2390        kernels.push_back({ it->first.c_str(),  getSourcePos(pseudoOpPlace) });
2391        auto info = formatHandler->getSectionInfo(currentSection);
2392        sections.push_back({ info.name, currentKernel, info.type, info.flags, 0,
2393                    0, info.relSpace });
2394        currentOutPos = 0;
2395    }
2396    else
2397    {
2398        // found
2399        try
2400        { formatHandler->setCurrentKernel(kmit->second); }
2401        catch(const AsmFormatException& ex) // if error
2402        {
2403            printError(pseudoOpPlace, ex.what());
2404            return;
2405        }
2406       
2407        currentOutPos = sections[currentSection].getSize();
2408    }
2409}
2410
2411void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
2412                            uint64_t align)
2413{
2414    const cxuint sectionId = formatHandler->getSectionId(sectionName);
2415    if (sectionId == ASMSECT_NONE)
2416    {
2417        // try to add new section
2418        cxuint sectionId;
2419        try
2420        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
2421        catch(const AsmFormatException& ex)
2422        {
2423            // error!
2424            printError(pseudoOpPlace, ex.what());
2425            return;
2426        }
2427        auto info = formatHandler->getSectionInfo(sectionId);
2428        sections.push_back({ info.name, currentKernel, info.type, info.flags, align,
2429                    0, info.relSpace });
2430        currentOutPos = 0;
2431    }
2432    else // if section exists
2433    {
2434        // found, try to set
2435        try
2436        { formatHandler->setCurrentSection(sectionId); }
2437        catch(const AsmFormatException& ex) // if error
2438        {
2439            printError(pseudoOpPlace, ex.what());
2440            return;
2441        }
2442       
2443        if (align!=0)
2444            printWarning(pseudoOpPlace, "Section alignment was ignored");
2445        currentOutPos = sections[currentSection].getSize();
2446    }
2447}
2448
2449// go to section, when not exists create it with specified alignment and flags
2450void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
2451        AsmSectionType type, Flags flags, uint64_t align)
2452{
2453    const cxuint sectionId = formatHandler->getSectionId(sectionName);
2454    if (sectionId == ASMSECT_NONE)
2455    {
2456        // try to add new section
2457        cxuint sectionId;
2458        try
2459        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
2460        catch(const AsmFormatException& ex)
2461        {
2462            // error!
2463            printError(pseudoOpPlace, ex.what());
2464            return;
2465        }
2466        auto info = formatHandler->getSectionInfo(sectionId);
2467        if (info.type == AsmSectionType::EXTRA_SECTION)
2468        {
2469            info.type = type;
2470            info.flags |= flags;
2471        }
2472        else
2473            printWarning(pseudoOpPlace,
2474                     "Section type and flags was ignored for builtin section");
2475        sections.push_back({ info.name, currentKernel, info.type, info.flags, align,
2476                    0, info.relSpace });
2477        currentOutPos = 0;
2478    }
2479    else // if section exists
2480    {
2481        // found, try to set
2482        try
2483        { formatHandler->setCurrentSection(sectionId); }
2484        catch(const AsmFormatException& ex) // if error
2485        {
2486            printError(pseudoOpPlace, ex.what());
2487            return;
2488        }
2489       
2490        printWarning(pseudoOpPlace, "Section type, flags and alignment was ignored");
2491        currentOutPos = sections[currentSection].getSize();
2492    }
2493}
2494
2495// go to section, when not exists create it with specified alignment
2496void Assembler::goToSection(const char* pseudoOpPlace, cxuint sectionId, uint64_t align)
2497{
2498    try
2499    { formatHandler->setCurrentSection(sectionId); }
2500    catch(const AsmFormatException& ex) // if error
2501    { printError(pseudoOpPlace, ex.what()); }
2502    if (sectionId >= sections.size())
2503    {
2504        auto info = formatHandler->getSectionInfo(sectionId);
2505        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
2506    }
2507    else if (align!=0)
2508        printWarning(pseudoOpPlace, "Section alignment was ignored");
2509   
2510    currentOutPos = sections[currentSection].getSize();
2511}
2512
2513// used in places, to initialize lazily (if needed) output format
2514void Assembler::initializeOutputFormat()
2515{
2516    if (formatHandler!=nullptr)
2517        return;
2518    switch(format)
2519    {
2520        case BinaryFormat::AMD:
2521            formatHandler = new AsmAmdHandler(*this);
2522            break;
2523        case BinaryFormat::AMDCL2:
2524            formatHandler = new AsmAmdCL2Handler(*this);
2525            break;
2526        case BinaryFormat::GALLIUM:
2527            formatHandler = new AsmGalliumHandler(*this);
2528            break;
2529        case BinaryFormat::ROCM:
2530            formatHandler = new AsmROCmHandler(*this);
2531            break;
2532        default:
2533            formatHandler = new AsmRawCodeHandler(*this);
2534            break;
2535    }
2536    isaAssembler = new GCNAssembler(*this);
2537    // add first section
2538    auto info = formatHandler->getSectionInfo(currentSection);
2539    sections.push_back({ info.name, currentKernel, info.type, info.flags, 0,
2540                0, info.relSpace });
2541    currentOutPos = 0;
2542}
2543
2544bool Assembler::getRegVar(const CString& name, const AsmRegVar*& regVar)
2545{ 
2546    regVar = nullptr;
2547    CString sameRvName;
2548    AsmScope* scope;
2549    auto it = findRegVarInScope(name, scope, sameRvName);
2550    if (it == nullptr)
2551        return false;
2552    regVar = &it->second;
2553    return true;
2554}
2555
2556void Assembler::handleRegionsOnKernels(const std::vector<cxuint>& newKernels,
2557                const std::vector<cxuint>& oldKernels, cxuint codeSection)
2558{
2559    auto oldit = oldKernels.begin();
2560    auto newit = newKernels.begin();
2561    auto olditend = oldKernels.end();
2562    auto newitend = newKernels.end();
2563   
2564    while (oldit != olditend || newit != newitend)
2565    {
2566        if (newit == newitend || (oldit != olditend &&  *oldit < *newit))
2567        {
2568            // no kernel in new set (close this region)
2569            kernels[*oldit].closeCodeRegion(sections[codeSection].content.size());
2570            ++oldit;
2571        }
2572        else if (oldit == olditend || (newit != newitend && *newit < *oldit))
2573        {
2574            // kernel in new set but not in old (open this region)
2575            kernels[*newit].openCodeRegion(sections[codeSection].content.size());
2576            ++newit;
2577        }
2578        else
2579        {
2580            // this same kernel in kernel, no changes
2581            ++oldit;
2582            ++newit;
2583        }
2584    }
2585}
2586
2587struct ScopeStackElem
2588{
2589    std::pair<CString, AsmScope*> scope;
2590    AsmScopeMap::iterator childIt;
2591};
2592
2593// try to resolve symbols in scope (after closing temporary scope or
2594// ending assembly for global scope)
2595void Assembler::tryToResolveSymbols(AsmScope* thisScope)
2596{
2597    std::deque<ScopeStackElem> scopeStack;
2598    std::pair<CString, AsmScope*> globalScopeEntry = { "", thisScope };
2599    scopeStack.push_back({ globalScopeEntry, thisScope->scopeMap.begin() });
2600   
2601    while (!scopeStack.empty())
2602    {
2603        ScopeStackElem& elem = scopeStack.back();
2604        if (elem.childIt == elem.scope.second->scopeMap.begin())
2605        {
2606            // first we check symbol of current scope
2607            AsmScope* curScope = elem.scope.second;
2608            for (AsmSymbolEntry& symEntry: curScope->symbolMap)
2609                if (!symEntry.second.occurrencesInExprs.empty() ||
2610                    (symEntry.first!="." &&
2611                            !isResolvableSection(symEntry.second.sectionId)))
2612                {
2613                    // try to resolve symbols
2614                    uint64_t value;
2615                    cxuint sectionId;
2616                    if (formatHandler!=nullptr &&
2617                        formatHandler->resolveSymbol(symEntry.second, value, sectionId))
2618                        setSymbol(symEntry, value, sectionId);
2619                }
2620        }
2621        // next, we travere on children
2622        if (elem.childIt != elem.scope.second->scopeMap.end())
2623        {
2624            scopeStack.push_back({ *elem.childIt,
2625                        elem.childIt->second->scopeMap.begin() });
2626            ++elem.childIt;
2627        }
2628        else // if end, we pop from stack
2629            scopeStack.pop_back();
2630    }
2631}
2632
2633// print unresolved symbols in global scope after assemblying
2634// or when popping temporary scope
2635void Assembler::printUnresolvedSymbols(AsmScope* thisScope)
2636{
2637    if ((flags&ASM_TESTRUN) != 0 && (flags&ASM_TESTRESOLVE) == 0)
2638        return;
2639   
2640    std::deque<ScopeStackElem> scopeStack;
2641    std::pair<CString, AsmScope*> globalScopeEntry = { "", thisScope };
2642    scopeStack.push_back({ globalScopeEntry, thisScope->scopeMap.begin() });
2643   
2644    while (!scopeStack.empty())
2645    {
2646        ScopeStackElem& elem = scopeStack.back();
2647        if (elem.childIt == elem.scope.second->scopeMap.begin())
2648        {
2649            // first we check symbol of current scope
2650            AsmScope* curScope = elem.scope.second;
2651            for (AsmSymbolEntry& symEntry: curScope->symbolMap)
2652                if (!symEntry.second.occurrencesInExprs.empty())
2653                    for (AsmExprSymbolOccurrence occur:
2654                            symEntry.second.occurrencesInExprs)
2655                    {
2656                        std::string scopePath;
2657                        auto it = scopeStack.begin(); // skip global scope
2658                        for (++it; it != scopeStack.end(); ++it)
2659                        {
2660                            // generate scope path
2661                            scopePath += it->scope.first.c_str();
2662                            scopePath += "::";
2663                        }
2664                        // print error, if symbol is unresolved
2665                        printError(occur.expression->getSourcePos(),(std::string(
2666                            "Unresolved symbol '")+scopePath+
2667                            symEntry.first.c_str()+"'").c_str());
2668                    }
2669        }
2670        // next, we travere on children
2671        if (elem.childIt != elem.scope.second->scopeMap.end())
2672        {
2673            scopeStack.push_back({ *elem.childIt,
2674                        elem.childIt->second->scopeMap.begin() });
2675            ++elem.childIt;
2676        }
2677        else // if end, we pop from stack
2678            scopeStack.pop_back();
2679    }
2680}
2681
2682bool Assembler::assemble()
2683{
2684    resolvingRelocs = false;
2685    sectionDiffsPrepared = false;
2686   
2687    for (const DefSym& defSym: defSyms)
2688        if (defSym.first!=".")
2689            globalScope.symbolMap[defSym.first] = AsmSymbol(ASMSECT_ABS, defSym.second);
2690        else if ((flags & ASM_WARNINGS) != 0)// ignore for '.'
2691            messageStream << "<command-line>: Warning: Definition for symbol '.' "
2692                    "was ignored" << std::endl;
2693   
2694    good = true;
2695    while (!endOfAssembly)
2696    {
2697        if (!lineAlreadyRead)
2698        {
2699            // read line
2700            if (!readLine())
2701                break;
2702        }
2703        else
2704        {
2705            // already line is read
2706            lineAlreadyRead = false;
2707            if (line == nullptr)
2708                break; // end of stream
2709        }
2710       
2711        const char* linePtr = line; // string points to place of line
2712        const char* end = line+lineSize;
2713        skipSpacesToEnd(linePtr, end);
2714        if (linePtr == end)
2715            continue; // only empty line
2716       
2717        // statement start (except labels). in this time can point to labels
2718        const char* stmtPlace = linePtr;
2719        CString firstName = extractLabelName(linePtr, end);
2720       
2721        skipSpacesToEnd(linePtr, end);
2722       
2723        bool doNextLine = false;
2724        while (!firstName.empty() && linePtr != end && *linePtr == ':' &&
2725                    (linePtr+1==end || linePtr[1]!=':'))
2726        {
2727            // labels
2728            linePtr++;
2729            skipSpacesToEnd(linePtr, end);
2730            initializeOutputFormat();
2731            if (firstName.front() >= '0' && firstName.front() <= '9')
2732            {
2733                // handle local labels
2734                if (sections.empty())
2735                {
2736                    printError(stmtPlace, "Local label can't be defined outside section");
2737                    doNextLine = true;
2738                    break;
2739                }
2740                if (!isAddressableSection())
2741                {
2742                    printError(stmtPlace, "Local label can't be defined in "
2743                            "non-addressable section ");
2744                    doNextLine = true;
2745                    break;
2746                }
2747                /* prevLRes - iterator to previous instance of local label (with 'b)
2748                 * nextLRes - iterator to next instance of local label (with 'f) */
2749                AsmSymbolEntry& prevLRes =
2750                        *globalScope.symbolMap.insert(std::make_pair(
2751                            std::string(firstName.c_str())+"b", AsmSymbol())).first;
2752                AsmSymbolEntry& nextLRes =
2753                        *globalScope.symbolMap.insert(std::make_pair(
2754                            std::string(firstName.c_str())+"f", AsmSymbol())).first;
2755                /* resolve forward symbol of label now */
2756                assert(setSymbol(nextLRes, currentOutPos, currentSection));
2757                // move symbol value from next local label into previous local label
2758                // clearOccurrences - obsolete - back local labels are undefined!
2759                prevLRes.second.value = nextLRes.second.value;
2760                prevLRes.second.hasValue = isResolvableSection();
2761                prevLRes.second.sectionId = currentSection;
2762                /// make forward symbol of label as undefined
2763                nextLRes.second.hasValue = false;
2764            }
2765            else
2766            {
2767                // regular labels
2768                if (firstName==".")
2769                {
2770                    printError(stmtPlace, "Symbol '.' can't be a label");
2771                    break;
2772                }
2773                /*std::pair<AsmSymbolMap::iterator, bool> res =
2774                        currentScope->symbolMap.insert(
2775                            std::make_pair(firstName, AsmSymbol()));*/
2776                std::pair<AsmSymbolEntry*, bool> res =
2777                            insertSymbolInScope(firstName, AsmSymbol());
2778                if (!res.second)
2779                {
2780                    // found
2781                    if (res.first->second.onceDefined && res.first->second.isDefined())
2782                    {
2783                        // if label
2784                        printError(stmtPlace, (std::string("Symbol '")+firstName.c_str()+
2785                                    "' is already defined").c_str());
2786                        doNextLine = true;
2787                        break;
2788                    }
2789                }
2790                if (sections.empty())
2791                {
2792                    printError(stmtPlace,
2793                               "Label can't be defined outside section");
2794                    doNextLine = true;
2795                    break;
2796                }
2797                if (!isAddressableSection())
2798                {
2799                    printError(stmtPlace, "Label can't be defined in "
2800                            "non-addressable section ");
2801                    doNextLine = true;
2802                    break;
2803                }
2804               
2805                setSymbol(*res.first, currentOutPos, currentSection);
2806                res.first->second.onceDefined = true;
2807                res.first->second.sectionId = currentSection;
2808               
2809                formatHandler->handleLabel(res.first->first);
2810            }
2811            // new label or statement
2812            stmtPlace = linePtr;
2813            firstName = extractLabelName(linePtr, end);
2814        }
2815        if (doNextLine)
2816            continue;
2817       
2818        /* now stmtStartStr - points to first string of statement
2819         * (labels has been skipped) */
2820        skipSpacesToEnd(linePtr, end);
2821        if (linePtr != end && *linePtr == '=' &&
2822            // not for local labels
2823            !isDigit(firstName.front()))
2824        {
2825            // assignment
2826            skipCharAndSpacesToEnd(linePtr, line+lineSize);
2827            if (linePtr == end)
2828            {
2829                printError(linePtr, "Expected assignment expression");
2830                continue;
2831            }
2832            assignSymbol(firstName, stmtPlace, linePtr);
2833            continue;
2834        }
2835        // make firstname as lowercase
2836        toLowerString(firstName);
2837       
2838        if (firstName.size() >= 2 && firstName[0] == '.') // check for pseudo-op
2839            parsePseudoOps(firstName, stmtPlace, linePtr);
2840        else if (firstName.size() >= 1 && isDigit(firstName[0]))
2841            printError(stmtPlace, "Illegal number at statement begin");
2842        else
2843        {
2844            // try to parse processor instruction or macro substitution
2845            if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
2846            { 
2847                if (firstName.empty()) // if name is empty
2848                {
2849                    if (linePtr!=end) // error
2850                        printError(stmtPlace, "Garbages at statement place");
2851                    continue;
2852                }
2853                initializeOutputFormat();
2854                // try parse instruction
2855                if (!isWriteableSection())
2856                {
2857                    printError(stmtPlace,
2858                       "Writing data into non-writeable section is illegal");
2859                    continue;
2860                }
2861               
2862                if (sections[currentSection].usageHandler == nullptr)
2863                    sections[currentSection].usageHandler.reset(
2864                            isaAssembler->createUsageHandler(
2865                                    sections[currentSection].content));
2866               
2867                isaAssembler->assemble(firstName, stmtPlace, linePtr, end,
2868                           sections[currentSection].content,
2869                           sections[currentSection].usageHandler.get());
2870                currentOutPos = sections[currentSection].getSize();
2871            }
2872        }
2873    }
2874    /* check clauses and print errors */
2875    while (!clauses.empty())
2876    {
2877        const AsmClause& clause = clauses.top();
2878        switch(clause.type)
2879        {
2880            case AsmClauseType::IF:
2881                printError(clause.sourcePos, "Unterminated '.if'");
2882                break;
2883            case AsmClauseType::ELSEIF:
2884                printError(clause.sourcePos, "Unterminated '.elseif'");
2885                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2886                break;
2887            case AsmClauseType::ELSE:
2888                printError(clause.sourcePos, "Unterminated '.else'");
2889                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2890                break;
2891            case AsmClauseType::MACRO:
2892                printError(clause.sourcePos, "Unterminated macro definition");
2893                break;
2894            case AsmClauseType::REPEAT:
2895                printError(clause.sourcePos, "Unterminated repetition");
2896            default:
2897                break;
2898        }
2899        clauses.pop();
2900    }
2901   
2902    if (withSectionDiffs())
2903    {
2904        formatHandler->prepareSectionDiffsResolving();
2905        sectionDiffsPrepared = true;
2906    }
2907   
2908    resolvingRelocs = true;
2909    tryToResolveSymbols(&globalScope);
2910   
2911    if (withSectionDiffs())
2912    {
2913        resolvingRelocs = false;
2914        for (AsmExpression*& expr: unevalExpressions)
2915        {
2916            // try to resolve unevaluated expressions
2917            uint64_t value;
2918            cxuint sectionId;
2919            if (expr->evaluate(*this, value, sectionId))
2920                resolveExprTarget(expr, value, sectionId);
2921            delete expr;
2922            expr = nullptr;
2923        }
2924        resolvingRelocs = true;
2925    }
2926   
2927    printUnresolvedSymbols(&globalScope);
2928   
2929    if (good && formatHandler!=nullptr)
2930    {
2931        // flushing regvar usage handlers
2932        for(AsmSection& section: sections)
2933            if (section.usageHandler!=nullptr)
2934                section.usageHandler->flush();
2935       
2936        // code opened regions for kernels
2937        for (cxuint i = 0; i < kernels.size(); i++)
2938        {
2939            currentKernel = i;
2940            cxuint sectionId = formatHandler->getSectionId(".text");
2941            if (sectionId == ASMSECT_NONE)
2942            {
2943                currentKernel = ASMKERN_GLOBAL;
2944                sectionId = formatHandler->getSectionId(".text");
2945            }
2946            kernels[i].closeCodeRegion(sections[sectionId].content.size());
2947        }
2948        // prepare binary
2949        formatHandler->prepareBinary();
2950    }
2951    return good;
2952}
2953
2954void Assembler::writeBinary(const char* filename) const
2955{
2956    if (good)
2957    {
2958        const AsmFormatHandler* formatHandler = getFormatHandler();
2959        if (formatHandler!=nullptr)
2960        {
2961            std::ofstream ofs(filename, std::ios::binary);
2962            if (ofs)
2963                formatHandler->writeBinary(ofs);
2964            else
2965                throw AsmException(std::string("Can't open output file '")+filename+"'");
2966        }
2967        else
2968            throw AsmException("No output binary");
2969    }
2970    else // failed
2971        throw AsmException("Assembler failed!");
2972}
2973
2974void Assembler::writeBinary(std::ostream& outStream) const
2975{
2976    if (good)
2977    {
2978        const AsmFormatHandler* formatHandler = getFormatHandler();
2979        if (formatHandler!=nullptr)
2980            formatHandler->writeBinary(outStream);
2981        else
2982            throw AsmException("No output binary");
2983    }
2984    else // failed
2985        throw AsmException("Assembler failed!");
2986}
2987
2988void Assembler::writeBinary(Array<cxbyte>& array) const
2989{
2990    if (good)
2991    {
2992        const AsmFormatHandler* formatHandler = getFormatHandler();
2993        if (formatHandler!=nullptr)
2994            formatHandler->writeBinary(array);
2995        else
2996            throw AsmException("No output binary");
2997    }
2998    else // failed
2999        throw AsmException("Assembler failed!");
3000}
Note: See TracBrowser for help on using the repository browser.