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

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

CLRadeonExtender: Asm: Prepping to '.for' implementation. Fixed undefSymbol: do not remove symbol from map:
previous behaviour causes invalid reads after evaluating '.eqv' symbol after required symbol to evaluation).

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