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

Last change on this file since 3944 was 3944, checked in by matszpk, 13 months ago

CLRadeonExtender: Asm: Small optimization in AsmScope? destructor.

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