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

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

CLRadeonExtender: Asm: Small fix.

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