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

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

CLRadeonExtender: AsmROCm: Accept '.arg' without access qualifiers (use default access qualifier if not included).
Asm: Add errorWhenNoEnd to skipComma.

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