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

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

CLRadeonExtender: Asm: First working AsmROCm with section differences.

File size: 104.4 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                    if (!expr->evaluate(*this, value, sectionId))
1434                    {
1435                        // if failed
1436                        delete occurrence.expression; // delete expression
1437                        good = false;
1438                        continue;
1439                    }
1440                }
1441                // resolve expression if at resolving symbol phase
1442                else if (formatHandler==nullptr ||
1443                        !formatHandler->resolveRelocation(expr, value, sectionId))
1444                {
1445                    // if failed
1446                    delete occurrence.expression; // delete expression
1447                    good = false;
1448                    continue;
1449                }
1450               
1451                // resolving
1452                if (target.type == ASMXTGT_SYMBOL)
1453                {    // resolve symbol
1454                    AsmSymbolEntry& curSymEntry = *target.symbol;
1455                    if (!curSymEntry.second.resolving &&
1456                        (!curSymEntry.second.regRange &&
1457                            curSymEntry.second.expression==expr))
1458                    {
1459                        curSymEntry.second.value = value;
1460                        curSymEntry.second.sectionId = sectionId;
1461                        curSymEntry.second.hasValue =
1462                            isResolvableSection(sectionId) || resolvingRelocs;
1463                        symbolStack.push(std::make_pair(&curSymEntry, 0));
1464                        if (!curSymEntry.second.hasValue)
1465                            continue;
1466                        curSymEntry.second.resolving = true;
1467                    }
1468                    // otherwise we ignore circular dependencies
1469                }
1470                else
1471                    good &= resolveExprTarget(expr, value, sectionId);
1472                delete occurrence.expression; // delete expression
1473            }
1474            else // otherwise we only clear occurrence expression
1475                occurrence.expression = nullptr; // clear expression
1476        }
1477        else // pop
1478        {
1479            entry.first->second.resolving = false;
1480            entry.first->second.occurrencesInExprs.clear();
1481            if (entry.first->second.snapshot && --(entry.first->second.refCount) == 0)
1482            {
1483                symbolSnapshots.erase(entry.first);
1484                delete entry.first; // delete this symbol snapshot
1485            }
1486            symbolStack.pop();
1487        }
1488    }
1489    return good;
1490}
1491
1492bool Assembler::assignSymbol(const CString& symbolName, const char* symbolPlace,
1493             const char* linePtr, bool reassign, bool baseExpr)
1494{
1495    skipSpacesToEnd(linePtr, line+lineSize);
1496    size_t symNameLength = symbolName.size();
1497    if (symNameLength >= 3 && symbolName.compare(symNameLength-3, 3, "::.")==0)
1498        THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' can be only in global scope")
1499   
1500    if (linePtr!=line+lineSize && *linePtr=='%')
1501    {
1502        if (symbolName == ".")
1503            THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' requires a resolved expression")
1504        initializeOutputFormat();
1505        ++linePtr;
1506        cxuint regStart, regEnd;
1507        const AsmRegVar* regVar;
1508        if (!isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar))
1509            return false;
1510        skipSpacesToEnd(linePtr, line+lineSize);
1511        if (linePtr != line+lineSize)
1512            THIS_FAIL_BY_ERROR(linePtr, "Garbages at end of expression")
1513       
1514        std::pair<AsmSymbolEntry*, bool> res =
1515                insertSymbolInScope(symbolName, AsmSymbol());
1516        if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1517            res.first->second.isDefined()))
1518        {
1519            // found and can be only once defined
1520            printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1521                        "' is already defined").c_str());
1522            return false;
1523        }
1524        if (!res.first->second.occurrencesInExprs.empty())
1525        {
1526            // regrange found in expressions (error)
1527            std::vector<std::pair<const AsmExpression*, size_t> > exprs;
1528            size_t i = 0;
1529            for (AsmExprSymbolOccurrence occur: res.first->second.occurrencesInExprs)
1530                exprs.push_back(std::make_pair(occur.expression, i++));
1531            // remove duplicates
1532            // sort by value
1533            std::sort(exprs.begin(), exprs.end(),
1534                      [](const std::pair<const AsmExpression*, size_t>& a,
1535                         const std::pair<const AsmExpression*, size_t>& b)
1536                    {
1537                        if (a.first==b.first)
1538                            return a.second<b.second;
1539                        return a.first<b.first;
1540                    });
1541            // make unique and resize (remove duplicates
1542            exprs.resize(std::unique(exprs.begin(), exprs.end(),
1543                       [](const std::pair<const AsmExpression*, size_t>& a,
1544                         const std::pair<const AsmExpression*, size_t>& b)
1545                       { return a.first==b.first; })-exprs.begin());
1546            // sort by occurrence
1547            std::sort(exprs.begin(), exprs.end(),
1548                      [](const std::pair<const AsmExpression*, size_t>& a,
1549                         const std::pair<const AsmExpression*, size_t>& b)
1550                    { return a.second<b.second; });
1551            // print errors (in order without duplicates)
1552            for (std::pair<const AsmExpression*, size_t> elem: exprs)
1553                printError(elem.first->getSourcePos(), "Expression have register symbol");
1554           
1555            printError(symbolPlace, (std::string("Register range symbol '") +
1556                            symbolName.c_str() + "' was used in some expressions").c_str());
1557            return false;
1558        }
1559        // setup symbol entry (required)
1560        AsmSymbolEntry& symEntry = *res.first;
1561        symEntry.second.expression = nullptr;
1562        symEntry.second.regVar = regVar;
1563        symEntry.second.onceDefined = !reassign;
1564        symEntry.second.base = false;
1565        symEntry.second.sectionId = ASMSECT_ABS;
1566        symEntry.second.regRange = symEntry.second.hasValue = true;
1567        symEntry.second.value = (regStart | (uint64_t(regEnd)<<32));
1568        return true;
1569    }
1570   
1571    const char* exprPlace = linePtr;
1572    // make base expr if baseExpr=true and symbolName is not output counter
1573    bool makeBaseExpr = (baseExpr && symbolName != ".");
1574   
1575    std::unique_ptr<AsmExpression> expr;
1576    uint64_t value;
1577    cxuint sectionId = ASMSECT_ABS;
1578    if (makeBaseExpr || !AsmExpression::fastExprEvaluate(*this, linePtr, value))
1579    {
1580        expr.reset(AsmExpression::parse(*this, linePtr, makeBaseExpr));
1581        if (!expr) // no expression, errors
1582            return false;
1583    }
1584   
1585    if (linePtr != line+lineSize)
1586        THIS_FAIL_BY_ERROR(linePtr, "Garbages at end of expression")
1587    if (expr && expr->isEmpty()) // empty expression, we treat as error
1588        THIS_FAIL_BY_ERROR(exprPlace, "Expected assignment expression")
1589   
1590    if (symbolName == ".")
1591    {
1592        // assigning '.'
1593        if (!expr) // if fast path
1594            return assignOutputCounter(symbolPlace, value, sectionId);
1595        if (!expr->evaluate(*this, value, sectionId))
1596            return false;
1597        if (expr->getSymOccursNum()==0)
1598            return assignOutputCounter(symbolPlace, value, sectionId);
1599        else
1600            THIS_FAIL_BY_ERROR(symbolPlace, "Symbol '.' requires a resolved expression")
1601    }
1602   
1603    std::pair<AsmSymbolEntry*, bool> res = insertSymbolInScope(symbolName, AsmSymbol());
1604    if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1605        res.first->second.isDefined()))
1606    {
1607        // found and can be only once defined
1608        printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1609                    "' is already defined").c_str());
1610        return false;
1611    }
1612    AsmSymbolEntry& symEntry = *res.first;
1613   
1614    bool tryLater = false;
1615    if (!expr)
1616    {
1617        setSymbol(symEntry, value, sectionId);
1618        symEntry.second.onceDefined = !reassign;
1619    }
1620    else if (expr->getSymOccursNum()==0)
1621    {
1622        // can evalute, assign now
1623        uint64_t value;
1624        cxuint sectionId;
1625       
1626        AsmTryStatus evalStatus = expr->tryEvaluate(*this, value, sectionId,
1627                                    withSectionDiffs());
1628        if (evalStatus == AsmTryStatus::FAILED)
1629            return false;
1630        else if (evalStatus == AsmTryStatus::TRY_LATER)
1631            tryLater = true;
1632        else
1633        {   // success
1634            setSymbol(symEntry, value, sectionId);
1635            symEntry.second.onceDefined = !reassign;
1636        }
1637    }
1638    else
1639        tryLater = true;
1640   
1641    if (tryLater) // set expression
1642    {
1643        expr->setTarget(AsmExprTarget::symbolTarget(&symEntry));
1644        if (expr->getSymOccursNum() == 0)
1645            unevalExpressions.push_back(expr.get());
1646        symEntry.second.expression = expr.release();
1647        symEntry.second.regRange = symEntry.second.hasValue = false;
1648        symEntry.second.onceDefined = !reassign;
1649        symEntry.second.base = baseExpr;
1650        if (baseExpr && !symEntry.second.occurrencesInExprs.empty())
1651        {
1652            /* make snapshot now resolving dependencies */
1653            AsmSymbolEntry* tempSymEntry;
1654            if (!AsmExpression::makeSymbolSnapshot(*this, symEntry, tempSymEntry,
1655                    &symEntry.second.occurrencesInExprs[0].expression->getSourcePos()))
1656                return false;
1657            tempSymEntry->second.occurrencesInExprs =
1658                        symEntry.second.occurrencesInExprs;
1659            // clear occurrences after copy
1660            symEntry.second.occurrencesInExprs.clear();
1661            if (tempSymEntry->second.hasValue) // set symbol chain
1662                setSymbol(*tempSymEntry, tempSymEntry->second.value,
1663                          tempSymEntry->second.sectionId);
1664        }
1665    }
1666    return true;
1667}
1668
1669bool Assembler::assignOutputCounter(const char* symbolPlace, uint64_t value,
1670            cxuint sectionId, cxbyte fillValue)
1671{
1672    initializeOutputFormat();
1673    // checking conditions and fail if not satisfied
1674    if (currentSection != sectionId && sectionId != ASMSECT_ABS)
1675        THIS_FAIL_BY_ERROR(symbolPlace, "Illegal section change for symbol '.'")
1676    if (currentSection != ASMSECT_ABS && int64_t(currentOutPos) > int64_t(value))
1677        /* check attempt to move backwards only for section that is not absolute */
1678        THIS_FAIL_BY_ERROR(symbolPlace, "Attempt to move backwards")
1679    if (!isAddressableSection())
1680        THIS_FAIL_BY_ERROR(symbolPlace,
1681                   "Change output counter inside non-addressable section is illegal")
1682    if (currentSection==ASMSECT_ABS && fillValue!=0)
1683        printWarning(symbolPlace, "Fill value is ignored inside absolute section");
1684    if (value-currentOutPos!=0)
1685        reserveData(value-currentOutPos, fillValue);
1686    currentOutPos = value;
1687    return true;
1688}
1689
1690// skip symbol name, return false if not symbol
1691bool Assembler::skipSymbol(const char*& linePtr)
1692{
1693    const char* end = line+lineSize;
1694    skipSpacesToEnd(linePtr, end);
1695    const char* start = linePtr;
1696    if (linePtr != end)
1697    {
1698        /* skip only symbol name */
1699        if(isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.' || *linePtr == '$')
1700            for (linePtr++; linePtr != end && (isAlnum(*linePtr) || *linePtr == '_' ||
1701                 *linePtr == '.' || *linePtr == '$') ; linePtr++);
1702    }
1703    if (start == linePtr)
1704    {
1705        // this is not symbol name
1706        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
1707        printError(start, "Expected symbol name");
1708        return false;
1709    }
1710    return true;
1711}
1712
1713bool Assembler::isAbsoluteSymbol(const AsmSymbol& symbol) const
1714{
1715    if (symbol.sectionId == ASMSECT_ABS)
1716        return true;
1717    // otherwise check section
1718    if (sections.empty())
1719        return false; // fallback
1720    const AsmSection& section = sections[symbol.sectionId];
1721    return (section.flags&ASMSECT_ABS_ADDRESSABLE) != 0;
1722}
1723
1724void Assembler::printWarning(const AsmSourcePos& pos, const char* message)
1725{
1726    if ((flags & ASM_WARNINGS) == 0)
1727        return; // do nothing
1728    pos.print(messageStream);
1729    messageStream.write(": Warning: ", 11);
1730    messageStream.write(message, ::strlen(message));
1731    messageStream.put('\n');
1732}
1733
1734void Assembler::printError(const AsmSourcePos& pos, const char* message)
1735{
1736    good = false;
1737    pos.print(messageStream);
1738    messageStream.write(": Error: ", 9);
1739    messageStream.write(message, ::strlen(message));
1740    messageStream.put('\n');
1741}
1742
1743// special routine to printing warning when value out of range
1744void Assembler::printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
1745        cxbyte signess)
1746{
1747    if (bits < 64)
1748    {
1749        /* signess - WS_BOTH - check value range as signed value
1750         * WS_UNSIGNED - check value as unsigned value */
1751        if (signess == WS_BOTH &&
1752            !(int64_t(value) >= (1LL<<bits) || int64_t(value) < -(1LL<<(bits-1))))
1753            return;
1754        if (signess == WS_UNSIGNED && (value < (1ULL<<bits)))
1755            return;
1756        std::string warning = "Value ";
1757        char buf[32];
1758        itocstrCStyle(value, buf, 32, 16);
1759        warning += buf;
1760        warning += " truncated to ";
1761        itocstrCStyle(value&((1ULL<<bits)-1), buf, 32, 16);
1762        warning += buf;
1763        printWarning(pos, warning.c_str());
1764    }
1765}
1766
1767void Assembler::addIncludeDir(const CString& includeDir)
1768{
1769    includeDirs.push_back(includeDir);
1770}
1771
1772void Assembler::addInitialDefSym(const CString& symName, uint64_t value)
1773{
1774    defSyms.push_back({symName, value});
1775}
1776
1777// push clause to stack ('.ifXXX','macro','rept'), return true if no error
1778// for '.else' changes current clause
1779bool Assembler::pushClause(const char* string, AsmClauseType clauseType, bool satisfied,
1780               bool& included)
1781{
1782    if (clauseType == AsmClauseType::MACRO || clauseType == AsmClauseType::IF ||
1783        clauseType == AsmClauseType::REPEAT)
1784    {
1785        // add new clause
1786        clauses.push({ clauseType, getSourcePos(string), satisfied, { } });
1787        included = satisfied;
1788        return true;
1789    }
1790    if (clauses.empty())
1791    {
1792        // no clauses
1793        if (clauseType == AsmClauseType::ELSEIF)
1794            printError(string, "No '.if' before '.elseif");
1795        else // else
1796            printError(string, "No '.if' before '.else'");
1797        return false;
1798    }
1799    AsmClause& clause = clauses.top();
1800    switch(clause.type)
1801    {
1802        case AsmClauseType::ELSE:
1803            if (clauseType == AsmClauseType::ELSEIF)
1804                printError(string, "'.elseif' after '.else'");
1805            else // else
1806                printError(string, "Duplicate of '.else'");
1807            printError(clause.sourcePos, "here is previous '.else'"); 
1808            printError(clause.prevIfPos, "here is begin of conditional clause"); 
1809            return false;
1810        case AsmClauseType::MACRO:
1811            THIS_FAIL_BY_ERROR(string, clauseType == AsmClauseType::ELSEIF ?
1812                        "No '.if' before '.elseif' inside macro" :
1813                        "No '.if' before '.else' inside macro")
1814        case AsmClauseType::REPEAT:
1815            THIS_FAIL_BY_ERROR(string, clauseType == AsmClauseType::ELSEIF ?
1816                        "No '.if' before '.elseif' inside repetition" :
1817                        "No '.if' before '.else' inside repetition")
1818        default:
1819            break;
1820    }
1821    included = satisfied && !clause.condSatisfied;
1822    clause.condSatisfied |= included;
1823    if (clause.type == AsmClauseType::IF)
1824        clause.prevIfPos = clause.sourcePos;
1825    clause.type = clauseType;
1826    clause.sourcePos = getSourcePos(string);
1827    return true;
1828}
1829
1830// pop clause ('.endif','.endm','.endr') from stack
1831bool Assembler::popClause(const char* string, AsmClauseType clauseType)
1832{
1833    if (clauses.empty())
1834    {
1835        // no clauses
1836        if (clauseType == AsmClauseType::IF)
1837            printError(string, "No conditional before '.endif'");
1838        else if (clauseType == AsmClauseType::MACRO) // macro
1839            printError(string, "No '.macro' before '.endm'");
1840        else if (clauseType == AsmClauseType::REPEAT) // repeat
1841            printError(string, "No '.rept' before '.endr'");
1842        return false;
1843    }
1844    AsmClause& clause = clauses.top();
1845    // when macro, reepats or conditional finished by wrong pseudo-op
1846    // ('.macro' -> '.endif', etc)
1847    switch(clause.type)
1848    {
1849        case AsmClauseType::IF:
1850        case AsmClauseType::ELSE:
1851        case AsmClauseType::ELSEIF:
1852            if (clauseType == AsmClauseType::MACRO)
1853                THIS_FAIL_BY_ERROR(string, "Ending macro across conditionals")
1854            if (clauseType == AsmClauseType::REPEAT)
1855                THIS_FAIL_BY_ERROR(string, "Ending repetition across conditionals")
1856            break;
1857        case AsmClauseType::MACRO:
1858            if (clauseType == AsmClauseType::REPEAT)
1859                THIS_FAIL_BY_ERROR(string, "Ending repetition across macro")
1860            if (clauseType == AsmClauseType::IF)
1861                THIS_FAIL_BY_ERROR(string, "Ending conditional across macro")
1862            break;
1863        case AsmClauseType::REPEAT:
1864            if (clauseType == AsmClauseType::MACRO)
1865                THIS_FAIL_BY_ERROR(string, "Ending macro across repetition")
1866            if (clauseType == AsmClauseType::IF)
1867                THIS_FAIL_BY_ERROR(string, "Ending conditional across repetition")
1868            break;
1869        default:
1870            break;
1871    }
1872    clauses.pop();
1873    return true;
1874}
1875
1876Assembler::ParseState Assembler::makeMacroSubstitution(const char* linePtr)
1877{
1878    const char* end = line+lineSize;
1879    const char* macroStartPlace = linePtr;
1880   
1881    CString macroName = extractSymName(linePtr, end, false);
1882    if (macroName.empty())
1883        return ParseState::MISSING;
1884    if (macroCase)
1885        toLowerString(macroName);
1886    AsmMacroMap::const_iterator it = macroMap.find(macroName);
1887    if (it == macroMap.end())
1888        return ParseState::MISSING; // macro not found
1889   
1890    /* parse arguments */
1891    RefPtr<const AsmMacro> macro = it->second;
1892    const size_t macroArgsNum = macro->getArgsNum();
1893    bool good = true;
1894    AsmMacroInputFilter::MacroArgMap argMap(macroArgsNum);
1895    for (size_t i = 0; i < macroArgsNum; i++) // set name of args
1896        argMap[i].first = macro->getArg(i).name;
1897   
1898    for (size_t i = 0; i < macroArgsNum; i++)
1899    {
1900        const AsmMacroArg& arg = macro->getArg(i);
1901       
1902        skipSpacesToEnd(linePtr, end);
1903        if (linePtr!=end && *linePtr==',' && i!=0)
1904            skipCharAndSpacesToEnd(linePtr, end);
1905       
1906        std::string macroArg;
1907        const char* argPlace = linePtr;
1908        if (!arg.vararg)
1909        {
1910            // regular macro argument
1911            if (!parseMacroArgValue(linePtr, macroArg))
1912            {
1913                good = false;
1914                continue;
1915            }
1916        }
1917        else
1918        {
1919            /* parse variadic arguments, they requires ',' separator */
1920            bool argGood = true;
1921            while (linePtr != end)
1922            {
1923                if (!parseMacroArgValue(linePtr, macroArg))
1924                {
1925                    argGood = good = false;
1926                    break;
1927                }
1928                skipSpacesToEnd(linePtr, end);
1929                if (linePtr!=end)
1930                {
1931                    if(*linePtr==',')
1932                    {
1933                        skipCharAndSpacesToEnd(linePtr, end);
1934                        macroArg.push_back(',');
1935                    }
1936                    else
1937                    {
1938                        printError(linePtr, "Garbages at end of line");
1939                        argGood = good = false;
1940                        break;
1941                    }
1942                }
1943            }
1944            if (!argGood) // not so good
1945                continue;
1946        }
1947        argMap[i].second = macroArg;
1948        if (arg.required && argMap[i].second.empty())
1949        {
1950            // error, value required
1951            printError(argPlace, (std::string("Value required for macro argument '") +
1952                    arg.name.c_str() + '\'').c_str());
1953            good = false;
1954        }
1955        else if (argMap[i].second.empty())
1956            argMap[i].second = arg.defaultValue;
1957    }
1958   
1959    skipSpacesToEnd(linePtr, end);
1960    if (!good)
1961        return ParseState::FAILED;
1962    if (linePtr != end)
1963    {
1964        printError(linePtr, "Garbages at end of line");
1965        return ParseState::FAILED;
1966    }
1967   
1968    // check depth of macro substitution
1969    if (macroSubstLevel == 1000)
1970    {
1971        printError(macroStartPlace, "Macro substitution level is greater than 1000");
1972        return ParseState::FAILED;
1973    }
1974    // sort argmap before using
1975    mapSort(argMap.begin(), argMap.end());
1976    // create macro input filter and push to stack
1977    std::unique_ptr<AsmInputFilter> macroFilter(new AsmMacroInputFilter(macro,
1978            getSourcePos(macroStartPlace), std::move(argMap), macroCount++,
1979            alternateMacro));
1980    asmInputFilters.push(macroFilter.release());
1981    currentInputFilter = asmInputFilters.top();
1982    macroSubstLevel++;
1983    return ParseState::PARSED;
1984}
1985
1986struct ScopeUsingStackElem
1987{
1988    AsmScope* scope;
1989    std::list<AsmScope*>::iterator usingIt;
1990};
1991
1992// routine to find scope in scope (only traversing by '.using's)
1993AsmScope* Assembler::findScopeInScope(AsmScope* scope, const CString& scopeName,
1994                  std::unordered_set<AsmScope*>& scopeSet)
1995{
1996    if (!scopeSet.insert(scope).second)
1997        return nullptr;
1998    std::stack<ScopeUsingStackElem> usingStack;
1999    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2000    while (!usingStack.empty())
2001    {
2002        ScopeUsingStackElem& current = usingStack.top();
2003        AsmScope* curScope = current.scope;
2004        if (current.usingIt == curScope->usedScopes.begin())
2005        {
2006            // first we found in this scope
2007            auto it = curScope->scopeMap.find(scopeName);
2008            if (it != curScope->scopeMap.end())
2009                return it->second;
2010        }
2011        // next we find in used children
2012        if (current.usingIt != curScope->usedScopes.end())
2013        {
2014            AsmScope* child = *current.usingIt;
2015            if (scopeSet.insert(child).second) // we insert, new
2016                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2017            ++current.usingIt; // next
2018        }
2019        else // back
2020            usingStack.pop();
2021    }
2022    return nullptr;
2023}
2024
2025AsmScope* Assembler::getRecurScope(const CString& scopePlace, bool ignoreLast,
2026                    const char** lastStep)
2027{
2028    AsmScope* scope = currentScope;
2029    const char* str = scopePlace.c_str();
2030    if (*str==':' && str[1]==':')
2031    {
2032        // choose global scope
2033        scope = &globalScope;
2034        str += 2;
2035    }
2036   
2037    std::vector<CString> scopeTrack;
2038    const char* lastStepCur = str;
2039    while (*str != 0)
2040    {
2041        const char* scopeNameStr = str;
2042        while (*str!=':' && *str!=0) str++;
2043        if (*str==0 && ignoreLast) // ignore last
2044            break;
2045        scopeTrack.push_back(CString(scopeNameStr, str));
2046        if (*str==':' && str[1]==':')
2047            str += 2;
2048        lastStepCur = str;
2049    }
2050    if (lastStep != nullptr)
2051        *lastStep = lastStepCur;
2052    if (scopeTrack.empty()) // no scope path
2053        return scope;
2054   
2055    std::unordered_set<AsmScope*> scopeSet;
2056    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2057    {  // find this scope
2058        AsmScope* newScope = findScopeInScope(scope2, scopeTrack[0], scopeSet);
2059        if (newScope != nullptr)
2060        {
2061            scope = newScope->parent;
2062            break;
2063        }
2064    }
2065   
2066    // otherwise create in current/global scope
2067    for (const CString& name: scopeTrack)
2068        getScope(scope, name, scope);
2069    return scope;
2070}
2071
2072// internal routine to find symbol in scope (only traversing by '.using's)
2073AsmSymbolEntry* Assembler::findSymbolInScopeInt(AsmScope* scope,
2074                    const CString& symName, std::unordered_set<AsmScope*>& scopeSet)
2075{
2076    if (!scopeSet.insert(scope).second)
2077        return nullptr;
2078    std::stack<ScopeUsingStackElem> usingStack;
2079    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2080    while (!usingStack.empty())
2081    {
2082        ScopeUsingStackElem& current = usingStack.top();
2083        AsmScope* curScope = current.scope;
2084        if (current.usingIt == curScope->usedScopes.begin())
2085        {
2086            // first we found in this scope
2087            AsmSymbolMap::iterator it = curScope->symbolMap.find(symName);
2088            if (it != curScope->symbolMap.end())
2089                return &*it;
2090        }
2091        // next we find in used children
2092        if (current.usingIt != curScope->usedScopes.end())
2093        {
2094            AsmScope* child = *current.usingIt;
2095            if (scopeSet.insert(child).second) // we insert, new
2096                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2097            ++current.usingIt; // next
2098        }
2099        else // back
2100            usingStack.pop();
2101    }
2102    return nullptr;
2103}
2104
2105// real routine to find symbol in scope (traverse by all visible scopes)
2106AsmSymbolEntry* Assembler::findSymbolInScope(const CString& symName, AsmScope*& scope,
2107            CString& sameSymName, bool insertMode)
2108{
2109    const char* lastStep = nullptr;
2110    scope = getRecurScope(symName, true, &lastStep);
2111    std::unordered_set<AsmScope*> scopeSet;
2112    AsmSymbolEntry* foundSym = findSymbolInScopeInt(scope, lastStep, scopeSet);
2113    sameSymName = lastStep;
2114    if (foundSym != nullptr)
2115        return foundSym;
2116    if (lastStep != symName)
2117        return nullptr;
2118    // otherwise is symName is not normal symName
2119    scope = currentScope;
2120    if (insertMode)
2121        return nullptr;
2122   
2123    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2124    {  // find this scope
2125        foundSym = findSymbolInScopeInt(scope2, lastStep, scopeSet);
2126        if (foundSym != nullptr)
2127            return foundSym;
2128    }
2129    return nullptr;
2130}
2131
2132std::pair<AsmSymbolEntry*, bool> Assembler::insertSymbolInScope(const CString& symName,
2133                 const AsmSymbol& symbol)
2134{
2135    AsmScope* outScope;
2136    CString sameSymName;
2137    AsmSymbolEntry* symEntry = findSymbolInScope(symName, outScope, sameSymName, true);
2138    if (symEntry==nullptr)
2139    {
2140        auto res = outScope->symbolMap.insert({ sameSymName, symbol });
2141        return std::make_pair(&*res.first, res.second);
2142    }
2143    return std::make_pair(symEntry, false);
2144}
2145
2146// internal routine to find regvar in scope (only traversing by '.using's)
2147AsmRegVarEntry* Assembler::findRegVarInScopeInt(AsmScope* scope, const CString& rvName,
2148                std::unordered_set<AsmScope*>& scopeSet)
2149{
2150    if (!scopeSet.insert(scope).second)
2151        return nullptr;
2152    std::stack<ScopeUsingStackElem> usingStack;
2153    usingStack.push(ScopeUsingStackElem{ scope, scope->usedScopes.begin() });
2154    while (!usingStack.empty())
2155    {
2156        ScopeUsingStackElem& current = usingStack.top();
2157        AsmScope* curScope = current.scope;
2158        if (current.usingIt == curScope->usedScopes.begin())
2159        {
2160            // first we found in this scope
2161            AsmRegVarMap::iterator it = curScope->regVarMap.find(rvName);
2162            if (it != curScope->regVarMap.end())
2163                return &*it;
2164        }
2165        // next we find in used children
2166        if (current.usingIt != curScope->usedScopes.end())
2167        {
2168            AsmScope* child = *current.usingIt;
2169            if (scopeSet.insert(child).second) // we insert, new
2170                usingStack.push(ScopeUsingStackElem{ child, child->usedScopes.begin() });
2171            ++current.usingIt; // next
2172        }
2173        else // back
2174            usingStack.pop();
2175    }
2176    return nullptr;
2177}
2178
2179// real routine to find regvar in scope (traverse by all visible scopes)
2180AsmRegVarEntry* Assembler::findRegVarInScope(const CString& rvName, AsmScope*& scope,
2181                      CString& sameRvName, bool insertMode)
2182{
2183    const char* lastStep = nullptr;
2184    scope = getRecurScope(rvName, true, &lastStep);
2185    std::unordered_set<AsmScope*> scopeSet;
2186    AsmRegVarEntry* foundRv = findRegVarInScopeInt(scope, lastStep, scopeSet);
2187    sameRvName = lastStep;
2188    if (foundRv != nullptr)
2189        return foundRv;
2190    if (lastStep != rvName)
2191        return nullptr;
2192    // otherwise is rvName is not normal rvName
2193    scope = currentScope;
2194    if (insertMode)
2195        return nullptr;
2196   
2197    for (AsmScope* scope2 = scope; scope2 != nullptr; scope2 = scope2->parent)
2198    {  // find this scope
2199        foundRv = findRegVarInScopeInt(scope2, lastStep, scopeSet);
2200        if (foundRv != nullptr)
2201            return foundRv;
2202    }
2203    return nullptr;
2204}
2205
2206std::pair<AsmRegVarEntry*, bool> Assembler::insertRegVarInScope(const CString& rvName,
2207                 const AsmRegVar& regVar)
2208{
2209    AsmScope* outScope;
2210    CString sameRvName;
2211    AsmRegVarEntry* rvEntry = findRegVarInScope(rvName, outScope, sameRvName, true);
2212    if (rvEntry==nullptr)
2213    {
2214        auto res = outScope->regVarMap.insert({ sameRvName, regVar });
2215        return std::make_pair(&*res.first, res.second);
2216    }
2217    return std::make_pair(rvEntry, false);
2218}
2219
2220bool Assembler::getScope(AsmScope* parent, const CString& scopeName, AsmScope*& scope)
2221{
2222    std::unordered_set<AsmScope*> scopeSet;
2223    AsmScope* foundScope = findScopeInScope(parent, scopeName, scopeSet);
2224    if (foundScope != nullptr)
2225    {
2226        scope = foundScope;
2227        return false;
2228    }
2229    std::unique_ptr<AsmScope> newScope(new AsmScope(parent));
2230    auto res = parent->scopeMap.insert(std::make_pair(scopeName, newScope.get()));
2231    scope = newScope.release();
2232    return res.second;
2233}
2234
2235bool Assembler::pushScope(const CString& scopeName)
2236{
2237    if (scopeName.empty())
2238    {
2239        // temporary scope
2240        std::unique_ptr<AsmScope> newScope(new AsmScope(currentScope, true));
2241        currentScope->scopeMap.insert(std::make_pair("", newScope.get()));
2242        currentScope = newScope.release();
2243    }
2244    else
2245        getScope(currentScope, scopeName, currentScope);
2246    scopeStack.push(currentScope);
2247    return true; // always good even if scope exists
2248}
2249
2250bool Assembler::popScope()
2251{
2252    if (scopeStack.empty())
2253        return false; // can't pop scope
2254    if (currentScope->temporary)
2255    {
2256        // delete scope
2257        currentScope->parent->scopeMap.erase("");
2258        const bool oldResolvingRelocs = resolvingRelocs;
2259        resolvingRelocs = true; // allow to resolve relocations
2260        tryToResolveSymbols(currentScope);
2261        printUnresolvedSymbols(currentScope);
2262        resolvingRelocs = oldResolvingRelocs;
2263        currentScope->deleteSymbolsRecursively();
2264        abandonedScopes.push_back(currentScope);
2265    }
2266    scopeStack.pop();
2267    currentScope = (!scopeStack.empty()) ? scopeStack.top() : &globalScope;
2268    return true;
2269}
2270
2271bool Assembler::includeFile(const char* pseudoOpPlace, const std::string& filename)
2272{
2273    if (inclusionLevel == 500)
2274        THIS_FAIL_BY_ERROR(pseudoOpPlace, "Inclusion level is greater than 500")
2275    std::unique_ptr<AsmInputFilter> newInputFilter(new AsmStreamInputFilter(
2276                getSourcePos(pseudoOpPlace), filename));
2277    asmInputFilters.push(newInputFilter.release());
2278    currentInputFilter = asmInputFilters.top();
2279    inclusionLevel++;
2280    return true;
2281}
2282
2283bool Assembler::readLine()
2284{
2285    line = currentInputFilter->readLine(*this, lineSize);
2286    while (line == nullptr)
2287    {
2288        // no line
2289        if (asmInputFilters.size() > 1)
2290        {
2291            /* decrease some level of a nesting */
2292            if (currentInputFilter->getType() == AsmInputFilterType::MACROSUBST)
2293                macroSubstLevel--;
2294            else if (currentInputFilter->getType() == AsmInputFilterType::STREAM)
2295                inclusionLevel--;
2296            else if (currentInputFilter->getType() == AsmInputFilterType::REPEAT)
2297                repetitionLevel--;
2298            delete asmInputFilters.top();
2299            asmInputFilters.pop();
2300        }
2301        else if (filenameIndex<filenames.size())
2302        {
2303            /* handling input assembler that have many files */
2304            do {
2305                // delete previous filter
2306                delete asmInputFilters.top();
2307                asmInputFilters.pop();
2308                /// create new input filter
2309                std::unique_ptr<AsmStreamInputFilter> thatFilter(
2310                    new AsmStreamInputFilter(filenames[filenameIndex++]));
2311                asmInputFilters.push(thatFilter.get());
2312                currentInputFilter = thatFilter.release();
2313                line = currentInputFilter->readLine(*this, lineSize);
2314            } while (line==nullptr && filenameIndex<filenames.size());
2315           
2316            return (line!=nullptr);
2317        }
2318        else
2319            return false;
2320        currentInputFilter = asmInputFilters.top();
2321        line = currentInputFilter->readLine(*this, lineSize);
2322    }
2323    return true;
2324}
2325
2326// reserve data in current section and fill values (used by '.skip' or position movement)
2327cxbyte* Assembler::reserveData(size_t size, cxbyte fillValue)
2328{
2329    if (currentSection != ASMSECT_ABS)
2330    {
2331        size_t oldOutPos = currentOutPos;
2332        AsmSection& section = sections[currentSection];
2333        if ((section.flags & ASMSECT_WRITEABLE) == 0)
2334        {
2335             // non writeable, only change output position (do not fill)
2336            currentOutPos += size;
2337            section.size += size;
2338            return nullptr;
2339        }
2340        else
2341        {
2342            section.content.insert(section.content.end(), size, fillValue);
2343            currentOutPos += size;
2344            return section.content.data() + oldOutPos;
2345        }
2346    }
2347    else
2348    {
2349        currentOutPos += size;
2350        return nullptr;
2351    }
2352}
2353
2354
2355void Assembler::goToMain(const char* pseudoOpPlace)
2356{
2357    try
2358    { formatHandler->setCurrentKernel(ASMKERN_GLOBAL); }
2359    catch(const AsmFormatException& ex) // if error
2360    { printError(pseudoOpPlace, ex.what()); }
2361   
2362    currentOutPos = sections[currentSection].getSize();
2363}
2364
2365void Assembler::goToKernel(const char* pseudoOpPlace, const char* kernelName)
2366{
2367    auto kmit = kernelMap.find(kernelName);
2368    if (kmit == kernelMap.end())
2369    {
2370        // not found, add new kernel
2371        cxuint kernelId;
2372        try
2373        { kernelId = formatHandler->addKernel(kernelName); }
2374        catch(const AsmFormatException& ex)
2375        {
2376            // error!
2377            printError(pseudoOpPlace, ex.what());
2378            return;
2379        }
2380        // add new kernel entries and section entry
2381        auto it = kernelMap.insert(std::make_pair(kernelName, kernelId)).first;
2382        kernels.push_back({ it->first.c_str(),  getSourcePos(pseudoOpPlace) });
2383        auto info = formatHandler->getSectionInfo(currentSection);
2384        sections.push_back({ info.name, currentKernel, info.type, info.flags, 0,
2385                    0, info.relSpace });
2386        currentOutPos = 0;
2387    }
2388    else
2389    {
2390        // found
2391        try
2392        { formatHandler->setCurrentKernel(kmit->second); }
2393        catch(const AsmFormatException& ex) // if error
2394        {
2395            printError(pseudoOpPlace, ex.what());
2396            return;
2397        }
2398       
2399        currentOutPos = sections[currentSection].getSize();
2400    }
2401}
2402
2403void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
2404                            uint64_t align)
2405{
2406    const cxuint sectionId = formatHandler->getSectionId(sectionName);
2407    if (sectionId == ASMSECT_NONE)
2408    {
2409        // try to add new section
2410        cxuint sectionId;
2411        try
2412        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
2413        catch(const AsmFormatException& ex)
2414        {
2415            // error!
2416            printError(pseudoOpPlace, ex.what());
2417            return;
2418        }
2419        auto info = formatHandler->getSectionInfo(sectionId);
2420        sections.push_back({ info.name, currentKernel, info.type, info.flags, align,
2421                    0, info.relSpace });
2422        currentOutPos = 0;
2423    }
2424    else // if section exists
2425    {
2426        // found, try to set
2427        try
2428        { formatHandler->setCurrentSection(sectionId); }
2429        catch(const AsmFormatException& ex) // if error
2430        {
2431            printError(pseudoOpPlace, ex.what());
2432            return;
2433        }
2434       
2435        if (align!=0)
2436            printWarning(pseudoOpPlace, "Section alignment was ignored");
2437        currentOutPos = sections[currentSection].getSize();
2438    }
2439}
2440
2441// go to section, when not exists create it with specified alignment and flags
2442void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
2443        AsmSectionType type, Flags flags, uint64_t align)
2444{
2445    const cxuint sectionId = formatHandler->getSectionId(sectionName);
2446    if (sectionId == ASMSECT_NONE)
2447    {
2448        // try to add new section
2449        cxuint sectionId;
2450        try
2451        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
2452        catch(const AsmFormatException& ex)
2453        {
2454            // error!
2455            printError(pseudoOpPlace, ex.what());
2456            return;
2457        }
2458        auto info = formatHandler->getSectionInfo(sectionId);
2459        if (info.type == AsmSectionType::EXTRA_SECTION)
2460        {
2461            info.type = type;
2462            info.flags |= flags;
2463        }
2464        else
2465            printWarning(pseudoOpPlace,
2466                     "Section type and flags was ignored for builtin section");
2467        sections.push_back({ info.name, currentKernel, info.type, info.flags, align,
2468                    0, info.relSpace });
2469        currentOutPos = 0;
2470    }
2471    else // if section exists
2472    {
2473        // found, try to set
2474        try
2475        { formatHandler->setCurrentSection(sectionId); }
2476        catch(const AsmFormatException& ex) // if error
2477        {
2478            printError(pseudoOpPlace, ex.what());
2479            return;
2480        }
2481       
2482        printWarning(pseudoOpPlace, "Section type, flags and alignment was ignored");
2483        currentOutPos = sections[currentSection].getSize();
2484    }
2485}
2486
2487// go to section, when not exists create it with specified alignment
2488void Assembler::goToSection(const char* pseudoOpPlace, cxuint sectionId, uint64_t align)
2489{
2490    try
2491    { formatHandler->setCurrentSection(sectionId); }
2492    catch(const AsmFormatException& ex) // if error
2493    { printError(pseudoOpPlace, ex.what()); }
2494    if (sectionId >= sections.size())
2495    {
2496        auto info = formatHandler->getSectionInfo(sectionId);
2497        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
2498    }
2499    else if (align!=0)
2500        printWarning(pseudoOpPlace, "Section alignment was ignored");
2501   
2502    currentOutPos = sections[currentSection].getSize();
2503}
2504
2505// used in places, to initialize lazily (if needed) output format
2506void Assembler::initializeOutputFormat()
2507{
2508    if (formatHandler!=nullptr)
2509        return;
2510    switch(format)
2511    {
2512        case BinaryFormat::AMD:
2513            formatHandler = new AsmAmdHandler(*this);
2514            break;
2515        case BinaryFormat::AMDCL2:
2516            formatHandler = new AsmAmdCL2Handler(*this);
2517            break;
2518        case BinaryFormat::GALLIUM:
2519            formatHandler = new AsmGalliumHandler(*this);
2520            break;
2521        case BinaryFormat::ROCM:
2522            formatHandler = new AsmROCmHandler(*this);
2523            break;
2524        default:
2525            formatHandler = new AsmRawCodeHandler(*this);
2526            break;
2527    }
2528    isaAssembler = new GCNAssembler(*this);
2529    // add first section
2530    auto info = formatHandler->getSectionInfo(currentSection);
2531    sections.push_back({ info.name, currentKernel, info.type, info.flags, 0,
2532                0, info.relSpace });
2533    currentOutPos = 0;
2534}
2535
2536bool Assembler::getRegVar(const CString& name, const AsmRegVar*& regVar)
2537{ 
2538    regVar = nullptr;
2539    CString sameRvName;
2540    AsmScope* scope;
2541    auto it = findRegVarInScope(name, scope, sameRvName);
2542    if (it == nullptr)
2543        return false;
2544    regVar = &it->second;
2545    return true;
2546}
2547
2548void Assembler::handleRegionsOnKernels(const std::vector<cxuint>& newKernels,
2549                const std::vector<cxuint>& oldKernels, cxuint codeSection)
2550{
2551    auto oldit = oldKernels.begin();
2552    auto newit = newKernels.begin();
2553    auto olditend = oldKernels.end();
2554    auto newitend = newKernels.end();
2555   
2556    while (oldit != olditend || newit != newitend)
2557    {
2558        if (newit == newitend || (oldit != olditend &&  *oldit < *newit))
2559        {
2560            // no kernel in new set (close this region)
2561            kernels[*oldit].closeCodeRegion(sections[codeSection].content.size());
2562            ++oldit;
2563        }
2564        else if (oldit == olditend || (newit != newitend && *newit < *oldit))
2565        {
2566            // kernel in new set but not in old (open this region)
2567            kernels[*newit].openCodeRegion(sections[codeSection].content.size());
2568            ++newit;
2569        }
2570        else
2571        {
2572            // this same kernel in kernel, no changes
2573            ++oldit;
2574            ++newit;
2575        }
2576    }
2577}
2578
2579struct ScopeStackElem
2580{
2581    std::pair<CString, AsmScope*> scope;
2582    AsmScopeMap::iterator childIt;
2583};
2584
2585// try to resolve symbols in scope (after closing temporary scope or
2586// ending assembly for global scope)
2587void Assembler::tryToResolveSymbols(AsmScope* thisScope)
2588{
2589    std::deque<ScopeStackElem> scopeStack;
2590    std::pair<CString, AsmScope*> globalScopeEntry = { "", thisScope };
2591    scopeStack.push_back({ globalScopeEntry, thisScope->scopeMap.begin() });
2592   
2593    while (!scopeStack.empty())
2594    {
2595        ScopeStackElem& elem = scopeStack.back();
2596        if (elem.childIt == elem.scope.second->scopeMap.begin())
2597        {
2598            // first we check symbol of current scope
2599            AsmScope* curScope = elem.scope.second;
2600            for (AsmSymbolEntry& symEntry: curScope->symbolMap)
2601                if (!symEntry.second.occurrencesInExprs.empty() ||
2602                    (symEntry.first!="." &&
2603                            !isResolvableSection(symEntry.second.sectionId)))
2604                {
2605                    // try to resolve symbols
2606                    uint64_t value;
2607                    cxuint sectionId;
2608                    if (formatHandler!=nullptr &&
2609                        formatHandler->resolveSymbol(symEntry.second, value, sectionId))
2610                        setSymbol(symEntry, value, sectionId);
2611                }
2612        }
2613        // next, we travere on children
2614        if (elem.childIt != elem.scope.second->scopeMap.end())
2615        {
2616            scopeStack.push_back({ *elem.childIt,
2617                        elem.childIt->second->scopeMap.begin() });
2618            ++elem.childIt;
2619        }
2620        else // if end, we pop from stack
2621            scopeStack.pop_back();
2622    }
2623}
2624
2625// print unresolved symbols in global scope after assemblying
2626// or when popping temporary scope
2627void Assembler::printUnresolvedSymbols(AsmScope* thisScope)
2628{
2629    if ((flags&ASM_TESTRUN) != 0 && (flags&ASM_TESTRESOLVE) == 0)
2630        return;
2631   
2632    std::deque<ScopeStackElem> scopeStack;
2633    std::pair<CString, AsmScope*> globalScopeEntry = { "", thisScope };
2634    scopeStack.push_back({ globalScopeEntry, thisScope->scopeMap.begin() });
2635   
2636    while (!scopeStack.empty())
2637    {
2638        ScopeStackElem& elem = scopeStack.back();
2639        if (elem.childIt == elem.scope.second->scopeMap.begin())
2640        {
2641            // first we check symbol of current scope
2642            AsmScope* curScope = elem.scope.second;
2643            for (AsmSymbolEntry& symEntry: curScope->symbolMap)
2644                if (!symEntry.second.occurrencesInExprs.empty())
2645                    for (AsmExprSymbolOccurrence occur:
2646                            symEntry.second.occurrencesInExprs)
2647                    {
2648                        std::string scopePath;
2649                        auto it = scopeStack.begin(); // skip global scope
2650                        for (++it; it != scopeStack.end(); ++it)
2651                        {
2652                            // generate scope path
2653                            scopePath += it->scope.first.c_str();
2654                            scopePath += "::";
2655                        }
2656                        // print error, if symbol is unresolved
2657                        printError(occur.expression->getSourcePos(),(std::string(
2658                            "Unresolved symbol '")+scopePath+
2659                            symEntry.first.c_str()+"'").c_str());
2660                    }
2661        }
2662        // next, we travere on children
2663        if (elem.childIt != elem.scope.second->scopeMap.end())
2664        {
2665            scopeStack.push_back({ *elem.childIt,
2666                        elem.childIt->second->scopeMap.begin() });
2667            ++elem.childIt;
2668        }
2669        else // if end, we pop from stack
2670            scopeStack.pop_back();
2671    }
2672}
2673
2674bool Assembler::assemble()
2675{
2676    resolvingRelocs = false;
2677    sectionDiffsPrepared = false;
2678   
2679    for (const DefSym& defSym: defSyms)
2680        if (defSym.first!=".")
2681            globalScope.symbolMap[defSym.first] = AsmSymbol(ASMSECT_ABS, defSym.second);
2682        else if ((flags & ASM_WARNINGS) != 0)// ignore for '.'
2683            messageStream << "<command-line>: Warning: Definition for symbol '.' "
2684                    "was ignored" << std::endl;
2685   
2686    good = true;
2687    while (!endOfAssembly)
2688    {
2689        if (!lineAlreadyRead)
2690        {
2691            // read line
2692            if (!readLine())
2693                break;
2694        }
2695        else
2696        {
2697            // already line is read
2698            lineAlreadyRead = false;
2699            if (line == nullptr)
2700                break; // end of stream
2701        }
2702       
2703        const char* linePtr = line; // string points to place of line
2704        const char* end = line+lineSize;
2705        skipSpacesToEnd(linePtr, end);
2706        if (linePtr == end)
2707            continue; // only empty line
2708       
2709        // statement start (except labels). in this time can point to labels
2710        const char* stmtPlace = linePtr;
2711        CString firstName = extractLabelName(linePtr, end);
2712       
2713        skipSpacesToEnd(linePtr, end);
2714       
2715        bool doNextLine = false;
2716        while (!firstName.empty() && linePtr != end && *linePtr == ':' &&
2717                    (linePtr+1==end || linePtr[1]!=':'))
2718        {
2719            // labels
2720            linePtr++;
2721            skipSpacesToEnd(linePtr, end);
2722            initializeOutputFormat();
2723            if (firstName.front() >= '0' && firstName.front() <= '9')
2724            {
2725                // handle local labels
2726                if (sections.empty())
2727                {
2728                    printError(stmtPlace, "Local label can't be defined outside section");
2729                    doNextLine = true;
2730                    break;
2731                }
2732                if (!isAddressableSection())
2733                {
2734                    printError(stmtPlace, "Local label can't be defined in "
2735                            "non-addressable section ");
2736                    doNextLine = true;
2737                    break;
2738                }
2739                /* prevLRes - iterator to previous instance of local label (with 'b)
2740                 * nextLRes - iterator to next instance of local label (with 'f) */
2741                AsmSymbolEntry& prevLRes =
2742                        *globalScope.symbolMap.insert(std::make_pair(
2743                            std::string(firstName.c_str())+"b", AsmSymbol())).first;
2744                AsmSymbolEntry& nextLRes =
2745                        *globalScope.symbolMap.insert(std::make_pair(
2746                            std::string(firstName.c_str())+"f", AsmSymbol())).first;
2747                /* resolve forward symbol of label now */
2748                assert(setSymbol(nextLRes, currentOutPos, currentSection));
2749                // move symbol value from next local label into previous local label
2750                // clearOccurrences - obsolete - back local labels are undefined!
2751                prevLRes.second.value = nextLRes.second.value;
2752                prevLRes.second.hasValue = isResolvableSection();
2753                prevLRes.second.sectionId = currentSection;
2754                /// make forward symbol of label as undefined
2755                nextLRes.second.hasValue = false;
2756            }
2757            else
2758            {
2759                // regular labels
2760                if (firstName==".")
2761                {
2762                    printError(stmtPlace, "Symbol '.' can't be a label");
2763                    break;
2764                }
2765                /*std::pair<AsmSymbolMap::iterator, bool> res =
2766                        currentScope->symbolMap.insert(
2767                            std::make_pair(firstName, AsmSymbol()));*/
2768                std::pair<AsmSymbolEntry*, bool> res =
2769                            insertSymbolInScope(firstName, AsmSymbol());
2770                if (!res.second)
2771                {
2772                    // found
2773                    if (res.first->second.onceDefined && res.first->second.isDefined())
2774                    {
2775                        // if label
2776                        printError(stmtPlace, (std::string("Symbol '")+firstName.c_str()+
2777                                    "' is already defined").c_str());
2778                        doNextLine = true;
2779                        break;
2780                    }
2781                }
2782                if (sections.empty())
2783                {
2784                    printError(stmtPlace,
2785                               "Label can't be defined outside section");
2786                    doNextLine = true;
2787                    break;
2788                }
2789                if (!isAddressableSection())
2790                {
2791                    printError(stmtPlace, "Label can't be defined in "
2792                            "non-addressable section ");
2793                    doNextLine = true;
2794                    break;
2795                }
2796               
2797                setSymbol(*res.first, currentOutPos, currentSection);
2798                res.first->second.onceDefined = true;
2799                res.first->second.sectionId = currentSection;
2800               
2801                formatHandler->handleLabel(res.first->first);
2802            }
2803            // new label or statement
2804            stmtPlace = linePtr;
2805            firstName = extractLabelName(linePtr, end);
2806        }
2807        if (doNextLine)
2808            continue;
2809       
2810        /* now stmtStartStr - points to first string of statement
2811         * (labels has been skipped) */
2812        skipSpacesToEnd(linePtr, end);
2813        if (linePtr != end && *linePtr == '=' &&
2814            // not for local labels
2815            !isDigit(firstName.front()))
2816        {
2817            // assignment
2818            skipCharAndSpacesToEnd(linePtr, line+lineSize);
2819            if (linePtr == end)
2820            {
2821                printError(linePtr, "Expected assignment expression");
2822                continue;
2823            }
2824            assignSymbol(firstName, stmtPlace, linePtr);
2825            continue;
2826        }
2827        // make firstname as lowercase
2828        toLowerString(firstName);
2829       
2830        if (firstName.size() >= 2 && firstName[0] == '.') // check for pseudo-op
2831            parsePseudoOps(firstName, stmtPlace, linePtr);
2832        else if (firstName.size() >= 1 && isDigit(firstName[0]))
2833            printError(stmtPlace, "Illegal number at statement begin");
2834        else
2835        {
2836            // try to parse processor instruction or macro substitution
2837            if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
2838            { 
2839                if (firstName.empty()) // if name is empty
2840                {
2841                    if (linePtr!=end) // error
2842                        printError(stmtPlace, "Garbages at statement place");
2843                    continue;
2844                }
2845                initializeOutputFormat();
2846                // try parse instruction
2847                if (!isWriteableSection())
2848                {
2849                    printError(stmtPlace,
2850                       "Writing data into non-writeable section is illegal");
2851                    continue;
2852                }
2853               
2854                if (sections[currentSection].usageHandler == nullptr)
2855                    sections[currentSection].usageHandler.reset(
2856                            isaAssembler->createUsageHandler(
2857                                    sections[currentSection].content));
2858               
2859                isaAssembler->assemble(firstName, stmtPlace, linePtr, end,
2860                           sections[currentSection].content,
2861                           sections[currentSection].usageHandler.get());
2862                currentOutPos = sections[currentSection].getSize();
2863            }
2864        }
2865    }
2866    /* check clauses and print errors */
2867    while (!clauses.empty())
2868    {
2869        const AsmClause& clause = clauses.top();
2870        switch(clause.type)
2871        {
2872            case AsmClauseType::IF:
2873                printError(clause.sourcePos, "Unterminated '.if'");
2874                break;
2875            case AsmClauseType::ELSEIF:
2876                printError(clause.sourcePos, "Unterminated '.elseif'");
2877                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2878                break;
2879            case AsmClauseType::ELSE:
2880                printError(clause.sourcePos, "Unterminated '.else'");
2881                printError(clause.prevIfPos, "here is begin of conditional clause"); 
2882                break;
2883            case AsmClauseType::MACRO:
2884                printError(clause.sourcePos, "Unterminated macro definition");
2885                break;
2886            case AsmClauseType::REPEAT:
2887                printError(clause.sourcePos, "Unterminated repetition");
2888            default:
2889                break;
2890        }
2891        clauses.pop();
2892    }
2893   
2894    if (withSectionDiffs())
2895    {
2896        formatHandler->prepareSectionDiffsResolving();
2897        sectionDiffsPrepared = true;
2898    }
2899   
2900    resolvingRelocs = true;
2901    tryToResolveSymbols(&globalScope);
2902   
2903    if (withSectionDiffs())
2904    {
2905        resolvingRelocs = false;
2906        for (AsmExpression*& expr: unevalExpressions)
2907        {
2908            // try to resolve unevaluated expressions
2909            uint64_t value;
2910            cxuint sectionId;
2911            if (expr->evaluate(*this, value, sectionId))
2912                resolveExprTarget(expr, value, sectionId);
2913            delete expr;
2914            expr = nullptr;
2915        }
2916        resolvingRelocs = true;
2917    }
2918   
2919    printUnresolvedSymbols(&globalScope);
2920   
2921    if (good && formatHandler!=nullptr)
2922    {
2923        // flushing regvar usage handlers
2924        for(AsmSection& section: sections)
2925            if (section.usageHandler!=nullptr)
2926                section.usageHandler->flush();
2927       
2928        // code opened regions for kernels
2929        for (cxuint i = 0; i < kernels.size(); i++)
2930        {
2931            currentKernel = i;
2932            cxuint sectionId = formatHandler->getSectionId(".text");
2933            if (sectionId == ASMSECT_NONE)
2934            {
2935                currentKernel = ASMKERN_GLOBAL;
2936                sectionId = formatHandler->getSectionId(".text");
2937            }
2938            kernels[i].closeCodeRegion(sections[sectionId].content.size());
2939        }
2940        // prepare binary
2941        formatHandler->prepareBinary();
2942    }
2943    return good;
2944}
2945
2946void Assembler::writeBinary(const char* filename) const
2947{
2948    if (good)
2949    {
2950        const AsmFormatHandler* formatHandler = getFormatHandler();
2951        if (formatHandler!=nullptr)
2952        {
2953            std::ofstream ofs(filename, std::ios::binary);
2954            if (ofs)
2955                formatHandler->writeBinary(ofs);
2956            else
2957                throw AsmException(std::string("Can't open output file '")+filename+"'");
2958        }
2959        else
2960            throw AsmException("No output binary");
2961    }
2962    else // failed
2963        throw AsmException("Assembler failed!");
2964}
2965
2966void Assembler::writeBinary(std::ostream& outStream) const
2967{
2968    if (good)
2969    {
2970        const AsmFormatHandler* formatHandler = getFormatHandler();
2971        if (formatHandler!=nullptr)
2972            formatHandler->writeBinary(outStream);
2973        else
2974            throw AsmException("No output binary");
2975    }
2976    else // failed
2977        throw AsmException("Assembler failed!");
2978}
2979
2980void Assembler::writeBinary(Array<cxbyte>& array) const
2981{
2982    if (good)
2983    {
2984        const AsmFormatHandler* formatHandler = getFormatHandler();
2985        if (formatHandler!=nullptr)
2986            formatHandler->writeBinary(array);
2987        else
2988            throw AsmException("No output binary");
2989    }
2990    else // failed
2991        throw AsmException("Assembler failed!");
2992}
Note: See TracBrowser for help on using the repository browser.