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

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

CLRadeonExtender: Add ROCm format handler's first code.

File size: 72.1 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 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 <unordered_set>
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
35using namespace CLRX;
36
37bool AsmSection::addRegVar(const CString& name, const AsmRegVar& var)
38{ return regVars.insert(std::make_pair(name, var)).second; }
39
40bool AsmSection::getRegVar(const CString& name, const AsmRegVar*& regVar) const
41{ 
42    auto it = regVars.find(name);
43    if (it==regVars.end())
44        return false;
45    regVar = &it->second;
46    return true;
47}
48
49const cxbyte CLRX::tokenCharTable[96] =
50{
51    //' '   '!'   '"'   '#'   '$'   '%'   '&'   '''
52    0x00, 0x01, 0x02, 0x03, 0x90, 0x85, 0x06, 0x07,
53    //'('   ')'   '*'   '+'   ','   '-'   '.'   '/'
54    0x88, 0x88, 0x8a, 0x0b, 0x0c, 0x8d, 0x90, 0x0f,
55    //'0'   '1'   '2'   '3'   '4'   '5'   '6'   '7' 
56    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
57    //'8'   '9'   ':'   ';'   '<'   '='   '>'   '?'
58    0x90, 0x90, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
59    //'@'   'A'   'B'   'C'   'D'   'E'   'F'   'G'
60    0x26, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
61    //'H'   'I'   'J'   'K'   'L'   'M'   'N'   'O'
62    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
63    //'P'   'Q'   'R'   'S'   'T'   'U'   'V'   'W'
64    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
65    //'X'   'Y'   'Z'   '['   '\'   ']'   '^'   '_'
66    0x90, 0x90, 0x90, 0x91, 0x92, 0x93, 0x14, 0x90,
67    //'`'   'a'   'b'   'c'   'd'   'e'   'f'   'g'
68    0x16, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
69    //'h'   'i'   'j'   'k'   'l'   'm'   'n'   'o'
70    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
71    //'p'   'q'   'r'   's'   't'   'u'   'v'   'w'
72    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
73    //'x'   'y'   'z'   '{'   '|'   '}'   '~'   ''
74    0x90, 0x90, 0x90, 0x97, 0x18, 0x99, 0x1a, 0x1b
75};
76
77void CLRX::skipSpacesAndLabels(const char*& linePtr, const char* end)
78{
79    const char* stmtStart;
80    while (true)
81    {
82        skipSpacesToEnd(linePtr, end);
83        stmtStart = linePtr;
84        // skip labels and macro substitutions
85        while (linePtr!=end && (isAlnum(*linePtr) || *linePtr=='$' || *linePtr=='.' ||
86            *linePtr=='_' || *linePtr=='\\'))
87        {
88            if (*linePtr!='\\')
89                linePtr++;
90            else
91            {   /* handle \@ and \() for correct parsing */
92                linePtr++;
93                if (linePtr!=end)
94                {
95                    if (*linePtr=='@')
96                        linePtr++;
97                    if (*linePtr=='(')
98                    {
99                        linePtr++;
100                        if (linePtr!=end && *linePtr==')')
101                            linePtr++;
102                    }
103                }
104            }
105        }
106        skipSpacesToEnd(linePtr, end);
107        if (linePtr==end || *linePtr!=':')
108            break;
109        linePtr++; // skip ':'
110    }
111    linePtr = stmtStart;
112}
113
114bool AsmParseUtils::checkGarbagesAtEnd(Assembler& asmr, const char* linePtr)
115{
116    skipSpacesToEnd(linePtr, asmr.line + asmr.lineSize);
117    if (linePtr != asmr.line + asmr.lineSize)
118    {
119        asmr.printError(linePtr, "Garbages at end of line");
120        return false;
121    }
122    return true;
123}
124
125bool AsmParseUtils::getAbsoluteValueArg(Assembler& asmr, uint64_t& value,
126                      const char*& linePtr, bool requiredExpr)
127{
128    const char* end = asmr.line + asmr.lineSize;
129    skipSpacesToEnd(linePtr, end);
130    const char* exprPlace = linePtr;
131    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
132    if (expr == nullptr)
133        return false;
134    if (expr->isEmpty() && requiredExpr)
135    {
136        asmr.printError(exprPlace, "Expected expression");
137        return false;
138    }
139    if (expr->isEmpty()) // do not set if empty expression
140        return true;
141    cxuint sectionId; // for getting
142    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
143        return false;
144    else if (sectionId != ASMSECT_ABS)
145    {   // if not absolute value
146        asmr.printError(exprPlace, "Expression must be absolute!");
147        return false;
148    }
149    return true;
150}
151
152bool AsmParseUtils::getAnyValueArg(Assembler& asmr, uint64_t& value,
153                   cxuint& sectionId, const char*& linePtr)
154{
155    const char* end = asmr.line + asmr.lineSize;
156    skipSpacesToEnd(linePtr, end);
157    const char* exprPlace = linePtr;
158    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, true));
159    if (expr == nullptr)
160        return false;
161    if (expr->isEmpty())
162    {
163        asmr.printError(exprPlace, "Expected expression");
164        return false;
165    }
166    if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
167        return false;
168    return true;
169}
170
171bool AsmParseUtils::getJumpValueArg(Assembler& asmr, uint64_t& value,
172            std::unique_ptr<AsmExpression>& outTargetExpr, const char*& linePtr)
173{
174    const char* end = asmr.line + asmr.lineSize;
175    skipSpacesToEnd(linePtr, end);
176    const char* exprPlace = linePtr;
177    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr, false, false));
178    if (expr == nullptr)
179        return false;
180    if (expr->isEmpty())
181    {
182        asmr.printError(exprPlace, "Expected expression");
183        return false;
184    }
185    if (expr->getSymOccursNum()==0)
186    {
187        cxuint sectionId;
188        if (!expr->evaluate(asmr, value, sectionId)) // failed evaluation!
189            return false;
190        if (sectionId != asmr.currentSection)
191        {   // if jump outside current section (.text)
192            asmr.printError(exprPlace, "Jump over current section!");
193            return false;
194        }
195        return true;
196    }
197    else
198    {
199        outTargetExpr = std::move(expr);
200        return true;
201    }
202}
203
204bool AsmParseUtils::getNameArg(Assembler& asmr, CString& outStr, const char*& linePtr,
205            const char* objName, bool requiredArg, bool skipCommaAtError)
206{
207    const char* end = asmr.line + asmr.lineSize;
208    outStr.clear();
209    skipSpacesToEnd(linePtr, end);
210    if (linePtr == end)
211    {
212        if (!requiredArg)
213            return true; // succeed
214        asmr.printError(linePtr, (std::string("Expected ")+objName).c_str());
215        return false;
216    }
217    const char* nameStr = linePtr;
218    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
219    {
220        linePtr++;
221        while (linePtr != end && (isAlnum(*linePtr) ||
222            *linePtr == '_' || *linePtr == '.')) linePtr++;
223    }
224    else
225    {
226        if (!requiredArg)
227            return true; // succeed
228        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
229                        " place").c_str());
230        if (!skipCommaAtError)
231            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
232        else
233            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
234        return false;
235    }
236    outStr.assign(nameStr, linePtr);
237    return true;
238}
239
240bool AsmParseUtils::getNameArg(Assembler& asmr, size_t maxOutStrSize, char* outStr,
241               const char*& linePtr, const char* objName, bool requiredArg,
242               bool ignoreLongerName, bool skipCommaAtError)
243{
244    const char* end = asmr.line + asmr.lineSize;
245    skipSpacesToEnd(linePtr, end);
246    if (linePtr == end)
247    {
248        if (!requiredArg)
249        {
250            outStr[0] = 0;
251            return true; // succeed
252        }
253        asmr.printError(linePtr, (std::string("Expected ")+objName).c_str());
254        return false;
255    }
256    const char* nameStr = linePtr;
257    if (isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.')
258    {
259        linePtr++;
260        while (linePtr != end && (isAlnum(*linePtr) ||
261            *linePtr == '_' || *linePtr == '.')) linePtr++;
262    }
263    else
264    {
265        if (!requiredArg)
266        {
267            outStr[0] = 0;
268            return true; // succeed
269        }
270        asmr.printError(linePtr, (std::string("Some garbages at ")+objName+
271                " place").c_str());
272       
273        if (!skipCommaAtError)
274            while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
275        else
276            while (linePtr != end && !isSpace(*linePtr)) linePtr++;
277        return false;
278    }
279    if (maxOutStrSize-1 < size_t(linePtr-nameStr))
280    {
281        if (ignoreLongerName)
282        {   // return empty string
283            outStr[0] = 0; // null-char
284            return true;
285        }
286        asmr.printError(linePtr, (std::string(objName)+" is too long").c_str());
287        return false;
288    }
289    const size_t outStrSize = std::min(maxOutStrSize-1, size_t(linePtr-nameStr));
290    std::copy(nameStr, nameStr+outStrSize, outStr);
291    outStr[outStrSize] = 0; // null-char
292    return true;
293}
294
295bool AsmParseUtils::skipComma(Assembler& asmr, bool& haveComma, const char*& linePtr)
296{
297    const char* end = asmr.line + asmr.lineSize;
298    skipSpacesToEnd(linePtr, end);
299    if (linePtr == end)
300    {
301        haveComma = false;
302        return true;
303    }
304    if (*linePtr != ',')
305    {
306        asmr.printError(linePtr, "Expected ',' before argument");
307        return false;
308    }
309    linePtr++;
310    haveComma = true;
311    return true;
312}
313
314bool AsmParseUtils::skipRequiredComma(Assembler& asmr, const char*& linePtr)
315{
316    const char* end = asmr.line + asmr.lineSize;
317    skipSpacesToEnd(linePtr, end);
318    if (linePtr == end || *linePtr != ',')
319    {
320        asmr.printError(linePtr, "Expected ',' before argument");
321        return false;
322    }
323    linePtr++;
324    return true;
325}
326
327bool AsmParseUtils::skipCommaForMultipleArgs(Assembler& asmr, const char*& linePtr)
328{
329    const char* end = asmr.line + asmr.lineSize;
330    skipSpacesToEnd(linePtr, end); // spaces before ','
331    if (linePtr == end)
332        return false;
333    if (*linePtr != ',')
334    {
335        asmr.printError(linePtr, "Expected ',' before next value");
336        linePtr++;
337        return false;
338    }
339    else
340        skipCharAndSpacesToEnd(linePtr, end);
341    return true;
342}
343
344bool AsmParseUtils::getEnumeration(Assembler& asmr, const char*& linePtr,
345              const char* objName, size_t tableSize,
346              const std::pair<const char*, cxuint>* table, cxuint& value,
347              const char* prefix)
348{
349    const char* end = asmr.line + asmr.lineSize;
350    char name[72];
351    skipSpacesToEnd(linePtr, end);
352    const char* namePlace = linePtr;
353    if (getNameArg(asmr, 72, name, linePtr, objName))
354    {
355        toLowerString(name);
356        size_t namePos = 0;
357        if (prefix!=nullptr)
358        {
359            size_t psize = ::strlen(prefix);
360            namePos = ::memcmp(name, prefix, psize)==0 ? psize : 0;
361        }
362        cxuint index = binaryMapFind(table, table + tableSize, name+namePos, CStringLess())
363                        - table;
364        if (index != tableSize)
365            value = table[index].second;
366        else // end of this map
367        {
368            asmr.printError(namePlace, (std::string("Unknown ")+objName).c_str());
369            return false;
370        }
371        return true;
372    }
373    return false;
374}
375
376ISAAssembler::ISAAssembler(Assembler& _assembler) : assembler(_assembler)
377{ }
378
379ISAAssembler::~ISAAssembler()
380{ }
381
382void AsmSymbol::removeOccurrenceInExpr(AsmExpression* expr, size_t argIndex,
383               size_t opIndex)
384{
385    auto it = std::remove(occurrencesInExprs.begin(), occurrencesInExprs.end(),
386            AsmExprSymbolOccurrence{expr, argIndex, opIndex});
387    occurrencesInExprs.resize(it-occurrencesInExprs.begin());
388}
389
390void AsmSymbol::clearOccurrencesInExpr()
391{
392    /* iteration with index and occurrencesInExprs.size() is required for checking size
393     * after expression deletion that removes occurrences in exprs in this symbol */
394    for (size_t i = 0; i < occurrencesInExprs.size(); i++)
395    {
396        auto& occur = occurrencesInExprs[i];
397        if (occur.expression!=nullptr && !occur.expression->unrefSymOccursNum())
398        {   // delete and move back iteration by number of removed elements
399            const size_t oldSize = occurrencesInExprs.size();
400            AsmExpression* occurExpr = occur.expression;
401            occur.expression = nullptr;
402            delete occurExpr;
403            // subtract number of removed elements from counter
404            i -= oldSize-occurrencesInExprs.size();
405        }
406    }
407    occurrencesInExprs.clear();
408}
409
410void AsmSymbol::undefine()
411{
412    hasValue = false;
413    base = false;
414    delete expression;
415    expression = nullptr;
416    onceDefined = false;
417}
418
419/*
420 * Assembler
421 */
422
423Assembler::Assembler(const CString& filename, std::istream& input, Flags _flags,
424        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
425        std::ostream& _printStream)
426        : format(_format),
427          deviceType(_deviceType),
428          driverVersion(0),
429          _64bit(false),
430          isaAssembler(nullptr),
431          symbolMap({std::make_pair(".", AsmSymbol(0, uint64_t(0)))}),
432          flags(_flags), 
433          lineSize(0), line(nullptr),
434          endOfAssembly(false),
435          messageStream(msgStream),
436          printStream(_printStream),
437          // value reference and section reference from first symbol: '.'
438          currentSection(symbolMap.begin()->second.sectionId),
439          currentOutPos(symbolMap.begin()->second.value)
440{
441    filenameIndex = 0;
442    alternateMacro = (flags & ASM_ALTMACRO)!=0;
443    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
444    localCount = macroCount = inclusionLevel = 0;
445    macroSubstLevel = repetitionLevel = 0;
446    lineAlreadyRead = false;
447    good = true;
448    resolvingRelocs = false;
449    formatHandler = nullptr;
450    input.exceptions(std::ios::badbit);
451    std::unique_ptr<AsmInputFilter> thatInputFilter(
452                    new AsmStreamInputFilter(input, filename));
453    asmInputFilters.push(thatInputFilter.get());
454    currentInputFilter = thatInputFilter.release();
455}
456
457Assembler::Assembler(const Array<CString>& _filenames, Flags _flags,
458        BinaryFormat _format, GPUDeviceType _deviceType, std::ostream& msgStream,
459        std::ostream& _printStream)
460        : format(_format),
461          deviceType(_deviceType),
462          driverVersion(0),
463          _64bit(false),
464          isaAssembler(nullptr),
465          symbolMap({std::make_pair(".", AsmSymbol(0, uint64_t(0)))}),
466          flags(_flags), 
467          lineSize(0), line(nullptr),
468          endOfAssembly(false),
469          messageStream(msgStream),
470          printStream(_printStream),
471          // value reference and section reference from first symbol: '.'
472          currentSection(symbolMap.begin()->second.sectionId),
473          currentOutPos(symbolMap.begin()->second.value)
474{
475    filenameIndex = 0;
476    filenames = _filenames;
477    alternateMacro = (flags & ASM_ALTMACRO)!=0;
478    buggyFPLit = (flags & ASM_BUGGYFPLIT)!=0;
479    localCount = macroCount = inclusionLevel = 0;
480    macroSubstLevel = repetitionLevel = 0;
481    lineAlreadyRead = false;
482    good = true;
483    resolvingRelocs = false;
484    formatHandler = nullptr;
485    std::unique_ptr<AsmInputFilter> thatInputFilter(
486                new AsmStreamInputFilter(filenames[filenameIndex++]));
487    asmInputFilters.push(thatInputFilter.get());
488    currentInputFilter = thatInputFilter.release();
489}
490
491Assembler::~Assembler()
492{
493    delete formatHandler;
494    if (isaAssembler != nullptr)
495        delete isaAssembler;
496    while (!asmInputFilters.empty())
497    {
498        delete asmInputFilters.top();
499        asmInputFilters.pop();
500    }
501   
502    /// remove expressions before symbol map deletion
503    for (auto& entry: symbolMap)
504        entry.second.clearOccurrencesInExpr();
505    /// remove expressions before symbol snapshots
506    for (auto& entry: symbolSnapshots)
507        entry->second.clearOccurrencesInExpr();
508   
509    for (auto& entry: symbolSnapshots)
510        delete entry;
511}
512
513bool Assembler::parseString(std::string& strarray, const char*& linePtr)
514{
515    const char* end = line+lineSize;
516    const char* startPlace = linePtr;
517    skipSpacesToEnd(linePtr, end);
518    strarray.clear();
519    if (linePtr == end || *linePtr != '"')
520    {
521        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
522        printError(startPlace, "Expected string");
523        return false;
524    }
525    linePtr++;
526   
527    while (linePtr != end && *linePtr != '"')
528    {
529        if (*linePtr == '\\')
530        {   // escape
531            linePtr++;
532            uint16_t value;
533            if (linePtr == end)
534            {
535                printError(startPlace, "Unterminated character of string");
536                return false;
537            }
538            if (*linePtr == 'x')
539            {   // hex
540                const char* charPlace = linePtr-1;
541                linePtr++;
542                if (linePtr == end)
543                {
544                    printError(startPlace, "Unterminated character of string");
545                    return false;
546                }
547                value = 0;
548                if (isXDigit(*linePtr))
549                    for (; linePtr != end; linePtr++)
550                    {
551                        cxuint digit;
552                        if (*linePtr >= '0' && *linePtr <= '9')
553                            digit = *linePtr-'0';
554                        else if (*linePtr >= 'a' && *linePtr <= 'f')
555                            digit = *linePtr-'a'+10;
556                        else if (*linePtr >= 'A' && *linePtr <= 'F')
557                            digit = *linePtr-'A'+10;
558                        else
559                            break;
560                        value = (value<<4) + digit;
561                    }
562                else
563                {
564                    printError(charPlace, "Expected hexadecimal character code");
565                    return false;
566                }
567                value &= 0xff;
568            }
569            else if (isODigit(*linePtr))
570            {   // octal
571                value = 0;
572                const char* charPlace = linePtr-1;
573                for (cxuint i = 0; linePtr != end && i < 3; i++, linePtr++)
574                {
575                    if (!isODigit(*linePtr))
576                        break;
577                    value = (value<<3) + uint64_t(*linePtr-'0');
578                    if (value > 255)
579                    {
580                        printError(charPlace, "Octal code out of range");
581                        return false;
582                    }
583                }
584            }
585            else
586            {   // normal escapes
587                const char c = *linePtr++;
588                switch (c)
589                {
590                    case 'a':
591                        value = '\a';
592                        break;
593                    case 'b':
594                        value = '\b';
595                        break;
596                    case 'r':
597                        value = '\r';
598                        break;
599                    case 'n':
600                        value = '\n';
601                        break;
602                    case 'f':
603                        value = '\f';
604                        break;
605                    case 'v':
606                        value = '\v';
607                        break;
608                    case 't':
609                        value = '\t';
610                        break;
611                    case '\\':
612                        value = '\\';
613                        break;
614                    case '\'':
615                        value = '\'';
616                        break;
617                    case '\"':
618                        value = '\"';
619                        break;
620                    default:
621                        value = c;
622                }
623            }
624            strarray.push_back(value);
625        }
626        else // regular character
627            strarray.push_back(*linePtr++);
628    }
629    if (linePtr == end)
630    {
631        printError(startPlace, "Unterminated string");
632        return false;
633    }
634    linePtr++;
635    return true;
636}
637
638bool Assembler::parseLiteral(uint64_t& value, const char*& linePtr)
639{
640    const char* startPlace = linePtr;
641    const char* end = line+lineSize;
642    if (linePtr != end && *linePtr == '\'')
643    {
644        linePtr++;
645        if (linePtr == end)
646        {
647            printError(startPlace, "Unterminated character literal");
648            return false;
649        }
650        if (*linePtr == '\'')
651        {
652            printError(startPlace, "Empty character literal");
653            return false;
654        }
655       
656        if (*linePtr != '\\')
657        {
658            value = *linePtr++;
659            if (linePtr == end || *linePtr != '\'')
660            {
661                printError(startPlace, "Missing ''' at end of literal");
662                return false;
663            }
664            linePtr++;
665            return true;
666        }
667        else // escapes
668        {
669            linePtr++;
670            if (linePtr == end)
671            {
672                printError(startPlace, "Unterminated character literal");
673                return false;
674            }
675            if (*linePtr == 'x')
676            {   // hex
677                linePtr++;
678                if (linePtr == end)
679                {
680                    printError(startPlace, "Unterminated character literal");
681                    return false;
682                }
683                value = 0;
684                if (isXDigit(*linePtr))
685                    for (; linePtr != end; linePtr++)
686                    {
687                        cxuint digit;
688                        if (*linePtr >= '0' && *linePtr <= '9')
689                            digit = *linePtr-'0';
690                        else if (*linePtr >= 'a' && *linePtr <= 'f')
691                            digit = *linePtr-'a'+10;
692                        else if (*linePtr >= 'A' && *linePtr <= 'F')
693                            digit = *linePtr-'A'+10;
694                        else
695                            break; // end of literal
696                        value = (value<<4) + digit;
697                    }
698                else
699                {
700                    printError(startPlace, "Expected hexadecimal character code");
701                    return false;
702                }
703                value &= 0xff;
704            }
705            else if (isODigit(*linePtr))
706            {   // octal
707                value = 0;
708                for (cxuint i = 0; linePtr != end && i < 3 && *linePtr != '\'';
709                     i++, linePtr++)
710                {
711                    if (!isODigit(*linePtr))
712                    {
713                        printError(startPlace, "Expected octal character code");
714                        return false;
715                    }
716                    value = (value<<3) + uint64_t(*linePtr-'0');
717                    if (value > 255)
718                    {
719                        printError(startPlace, "Octal code out of range");
720                        return false;
721                    }
722                }
723            }
724            else
725            {   // normal escapes
726                const char c = *linePtr++;
727                switch (c)
728                {
729                    case 'a':
730                        value = '\a';
731                        break;
732                    case 'b':
733                        value = '\b';
734                        break;
735                    case 'r':
736                        value = '\r';
737                        break;
738                    case 'n':
739                        value = '\n';
740                        break;
741                    case 'f':
742                        value = '\f';
743                        break;
744                    case 'v':
745                        value = '\v';
746                        break;
747                    case 't':
748                        value = '\t';
749                        break;
750                    case '\\':
751                        value = '\\';
752                        break;
753                    case '\'':
754                        value = '\'';
755                        break;
756                    case '\"':
757                        value = '\"';
758                        break;
759                    default:
760                        value = c;
761                }
762            }
763            if (linePtr == end || *linePtr != '\'')
764            {
765                printError(startPlace, "Missing ''' at end of literal");
766                return false;
767            }
768            linePtr++;
769            return true;
770        }
771    }
772    try
773    { value = cstrtovCStyle<uint64_t>(startPlace, line+lineSize, linePtr); }
774    catch(const ParseException& ex)
775    {
776        printError(startPlace, ex.what());
777        return false;
778    }
779    return true;
780}
781
782Assembler::ParseState Assembler::parseSymbol(const char*& linePtr,
783                AsmSymbolEntry*& entry, bool localLabel, bool dontCreateSymbol)
784{
785    const char* startPlace = linePtr;
786    const CString symName = extractSymName(linePtr, line+lineSize, localLabel);
787    if (symName.empty())
788    {   // this is not symbol or a missing symbol
789        while (linePtr != line+lineSize && !isSpace(*linePtr) && *linePtr != ',')
790            linePtr++;
791        entry = nullptr;
792        return Assembler::ParseState::MISSING;
793    }
794    if (symName == ".") // any usage of '.' causes format initialization
795        initializeOutputFormat();
796   
797    Assembler::ParseState state = Assembler::ParseState::PARSED;
798    bool symHasValue;
799    if (!dontCreateSymbol)
800    {   // create symbol if not found
801        std::pair<AsmSymbolMap::iterator, bool> res =
802                symbolMap.insert(std::make_pair(symName, AsmSymbol()));
803        entry = &*res.first;
804        symHasValue = res.first->second.hasValue;
805    }
806    else
807    {   // only find symbol and set isDefined and entry
808        AsmSymbolMap::iterator it = symbolMap.find(symName);
809        entry = (it != symbolMap.end()) ? &*it : nullptr;
810        symHasValue = (it != symbolMap.end() && it->second.hasValue);
811    }
812    if (isDigit(symName.front()) && symName[linePtr-startPlace-1] == 'b' && !symHasValue)
813    {   // failed at finding
814        std::string error = "Undefined previous local label '";
815        error.append(symName.begin(), linePtr-startPlace);
816        error += "'";
817        printError(linePtr, error.c_str());
818        state = Assembler::ParseState::FAILED;
819    }
820   
821    return state;
822}
823
824bool Assembler::parseMacroArgValue(const char*& string, std::string& outStr)
825{
826    const char* end = line+lineSize;
827    bool firstNonSpace = false;
828    cxbyte prevTok = 0;
829    cxuint backslash = 0;
830   
831    if ((alternateMacro && string != end && *string=='%') ||
832        (!alternateMacro && string+2 <= end && *string=='\\' && string[1]=='%'))
833    {   // alternate syntax, parse expression evaluation
834        const char* exprPlace = string + ((alternateMacro) ? 1 : 2);
835        uint64_t value;
836        if (AsmParseUtils::getAbsoluteValueArg(*this, value, exprPlace, true))
837        {
838            char buf[32];
839            itocstrCStyle<int64_t>(value, buf, 32);
840            string = exprPlace;
841            outStr = buf;
842            return true;
843        }
844        else
845        {   /* if error */
846            string = exprPlace;
847            return false;
848        }
849    }
850   
851    if (alternateMacro && string != end && (*string=='<' || *string=='\'' || *string=='"'))
852    {   /* alternate string quoting */
853        const char termChar = (*string=='<') ? '>' : *string;
854        string++;
855        bool escape = false;
856        while (string != end && (*string != termChar || escape))
857        {
858            if (!escape && *string=='!')
859            {   /* skip this escaping */
860                escape = true;
861                string++;
862            }
863            else
864            {   /* put character */
865                escape = false;
866                outStr.push_back(*string++);
867            }
868        }
869        if (string == end)
870        {   /* if unterminated string */
871            printError(string, "Unterminated quoted string");
872            return false;
873        }
874        string++;
875        return true;
876    }
877    else if (string != end && *string=='"')
878    {
879        string++;
880        while (string != end && (*string != '\"' || (backslash&1)!=0))
881        {
882            if (*string=='\\')
883                backslash++;
884            else
885                backslash = 0;
886            outStr.push_back(*string++);
887        }
888        if (string == end)
889        {
890            printError(string, "Unterminated quoted string");
891            return false;
892        }
893        string++;
894        return true;
895    }
896   
897    for (; string != end && *string != ','; string++)
898    {
899        if(*string == '"') // quoted
900            return true; // next argument
901        if (!isSpace(*string))
902        {
903            const cxbyte thisTok = (cxbyte(*string) >= 0x20 && cxbyte(*string) < 0x80) ?
904                tokenCharTable[*string-0x20] : 0;
905            bool prevTokCont = (prevTok&0x80)!=0;
906            bool thisTokCont = (thisTok&0x80)!=0;
907            if (firstNonSpace && ((prevTok!=thisTok && !(thisTokCont ^ prevTokCont)) || 
908                (prevTok==thisTok && (thisTokCont&prevTokCont))))
909                break;  // end of token list for macro arg
910            outStr.push_back(*string);
911            firstNonSpace = false;
912            prevTok = thisTok;
913        }
914        else
915        {
916            firstNonSpace = true;
917            continue; // space
918        }
919    }
920    return true;
921}
922
923bool Assembler::setSymbol(AsmSymbolEntry& symEntry, uint64_t value, cxuint sectionId)
924{
925    symEntry.second.value = value;
926    symEntry.second.expression = nullptr;
927    symEntry.second.sectionId = sectionId;
928    symEntry.second.hasValue = isResolvableSection(sectionId) || resolvingRelocs;
929    symEntry.second.regRange = false;
930    symEntry.second.base = false;
931    if (!symEntry.second.hasValue) // if not resolved we just return
932        return true; // no error
933    bool good = true;
934   
935    // resolve value of pending symbols
936    std::stack<std::pair<AsmSymbolEntry*, size_t> > symbolStack;
937    symbolStack.push(std::make_pair(&symEntry, 0));
938    symEntry.second.resolving = true;
939   
940    while (!symbolStack.empty())
941    {
942        std::pair<AsmSymbolEntry*, size_t>& entry = symbolStack.top();
943        if (entry.second < entry.first->second.occurrencesInExprs.size())
944        {
945            AsmExprSymbolOccurrence& occurrence =
946                    entry.first->second.occurrencesInExprs[entry.second];
947            AsmExpression* expr = occurrence.expression;
948            expr->substituteOccurrence(occurrence, entry.first->second.value,
949                       (!isAbsoluteSymbol(entry.first->second)) ?
950                       entry.first->second.sectionId : ASMSECT_ABS);
951            entry.second++;
952           
953            if (!expr->unrefSymOccursNum())
954            {   // expresion has been fully resolved
955                uint64_t value;
956                cxuint sectionId;
957                const AsmExprTarget& target = expr->getTarget();
958                if (!resolvingRelocs || target.type==ASMXTGT_SYMBOL)
959                {   // standard mode
960                    if (!expr->evaluate(*this, value, sectionId))
961                    {   // if failed
962                        delete occurrence.expression; // delete expression
963                        good = false;
964                        continue;
965                    }
966                }
967                // resolve expression if at resolving symbol phase
968                else if (formatHandler==nullptr ||
969                        !formatHandler->resolveRelocation(expr, value, sectionId))
970                {   // if failed
971                    delete occurrence.expression; // delete expression
972                    good = false;
973                    continue;
974                }
975               
976                switch(target.type)
977                {
978                    case ASMXTGT_SYMBOL:
979                    {    // resolve symbol
980                        AsmSymbolEntry& curSymEntry = *target.symbol;
981                        if (!curSymEntry.second.resolving &&
982                            curSymEntry.second.expression==expr)
983                        {
984                            curSymEntry.second.value = value;
985                            curSymEntry.second.sectionId = sectionId;
986                            curSymEntry.second.hasValue =
987                                isResolvableSection(sectionId) || resolvingRelocs;
988                            symbolStack.push(std::make_pair(&curSymEntry, 0));
989                            if (!curSymEntry.second.hasValue)
990                                continue;
991                            curSymEntry.second.resolving = true;
992                        }
993                        // otherwise we ignore circular dependencies
994                        break;
995                    }
996                    case ASMXTGT_DATA8:
997                        if (sectionId != ASMSECT_ABS)
998                        {
999                            printError(expr->getSourcePos(),
1000                                   "Relative value is illegal in data expressions");
1001                            good = false;
1002                        }
1003                        else
1004                        {
1005                            printWarningForRange(8, value, expr->getSourcePos());
1006                            sections[target.sectionId].content[target.offset] =
1007                                    cxbyte(value);
1008                        }
1009                        break;
1010                    case ASMXTGT_DATA16:
1011                        if (sectionId != ASMSECT_ABS)
1012                        {
1013                            printError(expr->getSourcePos(),
1014                                   "Relative value is illegal in data expressions");
1015                            good = false;
1016                        }
1017                        else
1018                        {
1019                            printWarningForRange(16, value, expr->getSourcePos());
1020                            SULEV(*reinterpret_cast<uint16_t*>(sections[target.sectionId]
1021                                    .content.data() + target.offset), uint16_t(value));
1022                        }
1023                        break;
1024                    case ASMXTGT_DATA32:
1025                        if (sectionId != ASMSECT_ABS)
1026                        {
1027                            printError(expr->getSourcePos(),
1028                                   "Relative value is illegal in data expressions");
1029                            good = false;
1030                        }
1031                        else
1032                        {
1033                            printWarningForRange(32, value, expr->getSourcePos());
1034                            SULEV(*reinterpret_cast<uint32_t*>(sections[target.sectionId]
1035                                    .content.data() + target.offset), uint32_t(value));
1036                        }
1037                        break;
1038                    case ASMXTGT_DATA64:
1039                        if (sectionId != ASMSECT_ABS)
1040                        {
1041                            printError(expr->getSourcePos(),
1042                                   "Relative value is illegal in data expressions");
1043                            good = false;
1044                        }
1045                        else
1046                            SULEV(*reinterpret_cast<uint64_t*>(sections[target.sectionId]
1047                                    .content.data() + target.offset), uint64_t(value));
1048                        break;
1049                    default: // ISA assembler resolves this dependency
1050                        if (!isaAssembler->resolveCode(expr->getSourcePos(),
1051                                target.sectionId, sections[target.sectionId].content.data(),
1052                                target.offset, target.type, sectionId, value))
1053                            good = false;
1054                        break;
1055                }
1056                delete occurrence.expression; // delete expression
1057            }
1058            else // otherwise we only clear occurrence expression
1059                occurrence.expression = nullptr; // clear expression
1060        }
1061        else // pop
1062        {
1063            entry.first->second.resolving = false;
1064            entry.first->second.occurrencesInExprs.clear();
1065            if (entry.first->second.snapshot && --(entry.first->second.refCount) == 0)
1066            {
1067                symbolSnapshots.erase(entry.first);
1068                delete entry.first; // delete this symbol snapshot
1069            }
1070            symbolStack.pop();
1071        }
1072    }
1073    return good;
1074}
1075
1076bool Assembler::assignSymbol(const CString& symbolName, const char* symbolPlace,
1077             const char* linePtr, bool reassign, bool baseExpr)
1078{
1079    skipSpacesToEnd(linePtr, line+lineSize);
1080    if (linePtr!=line+lineSize && *linePtr=='%')
1081    {
1082        if (symbolName == ".")
1083        {
1084            printError(symbolPlace, "Symbol '.' requires a resolved expression");
1085            return false;
1086        }
1087        initializeOutputFormat();
1088        ++linePtr;
1089        cxuint regStart, regEnd;
1090        const AsmRegVar* regVar;
1091        if (!isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar))
1092            return false;
1093        skipSpacesToEnd(linePtr, line+lineSize);
1094        if (linePtr != line+lineSize)
1095        {
1096            printError(linePtr, "Garbages at end of expression");
1097            return false;
1098        }
1099       
1100        std::pair<AsmSymbolMap::iterator, bool> res =
1101                symbolMap.insert(std::make_pair(symbolName, AsmSymbol()));
1102        if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1103            res.first->second.isDefined()))
1104        {   // found and can be only once defined
1105            printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1106                        "' is already defined").c_str());
1107            return false;
1108        }
1109        if (!res.first->second.occurrencesInExprs.empty())
1110        {   // found in expressions
1111            std::vector<std::pair<const AsmExpression*, size_t> > exprs;
1112            size_t i = 0;
1113            for (AsmExprSymbolOccurrence occur: res.first->second.occurrencesInExprs)
1114                exprs.push_back(std::make_pair(occur.expression, i++));
1115            // remove duplicates
1116            std::sort(exprs.begin(), exprs.end(),
1117                      [](const std::pair<const AsmExpression*, size_t>& a,
1118                         const std::pair<const AsmExpression*, size_t>& b)
1119                    {
1120                        if (a.first==b.first)
1121                            return a.second<b.second;
1122                        return a.first<b.first;
1123                    });
1124            exprs.resize(std::unique(exprs.begin(), exprs.end(),
1125                       [](const std::pair<const AsmExpression*, size_t>& a,
1126                         const std::pair<const AsmExpression*, size_t>& b)
1127                       { return a.first==b.first; })-exprs.begin());
1128           
1129            std::sort(exprs.begin(), exprs.end(),
1130                      [](const std::pair<const AsmExpression*, size_t>& a,
1131                         const std::pair<const AsmExpression*, size_t>& b)
1132                    { return a.second<b.second; });
1133            // print errors
1134            for (std::pair<const AsmExpression*, size_t> elem: exprs)
1135                printError(elem.first->getSourcePos(), "Expression have register symbol");
1136           
1137            printError(symbolPlace, (std::string("Register range symbol '") +
1138                            symbolName.c_str() + "' was used in some expressions").c_str());
1139            return false;
1140        }
1141        // setup symbol entry (required)
1142        AsmSymbolEntry& symEntry = *res.first;
1143        symEntry.second.expression = nullptr;
1144        symEntry.second.onceDefined = !reassign;
1145        symEntry.second.base = false;
1146        symEntry.second.sectionId = ASMSECT_ABS;
1147        symEntry.second.regRange = symEntry.second.hasValue = true;
1148        symEntry.second.value = (regStart | (uint64_t(regEnd)<<32));
1149        return true;
1150    }
1151   
1152    const char* exprPlace = linePtr;
1153    // make base expr if baseExpr=true and symbolName is not output counter
1154    bool makeBaseExpr = (baseExpr && symbolName != ".");
1155    std::unique_ptr<AsmExpression> expr(AsmExpression::parse(*this, linePtr, makeBaseExpr));
1156    if (!expr) // no expression, errors
1157        return false;
1158   
1159    if (linePtr != line+lineSize)
1160    {
1161        printError(linePtr, "Garbages at end of expression");
1162        return false;
1163    }
1164    if (expr->isEmpty()) // empty expression, we treat as error
1165    {
1166        printError(exprPlace, "Expected assignment expression");
1167        return false;
1168    }
1169   
1170    if (symbolName == ".")
1171    {   // assigning '.'
1172        uint64_t value;
1173        cxuint sectionId;
1174        if (!expr->evaluate(*this, value, sectionId))
1175            return false;
1176        if (expr->getSymOccursNum()==0)
1177            return assignOutputCounter(symbolPlace, value, sectionId);
1178        else
1179        {
1180            printError(symbolPlace, "Symbol '.' requires a resolved expression");
1181            return false;
1182        }
1183    }
1184   
1185    std::pair<AsmSymbolMap::iterator, bool> res =
1186            symbolMap.insert(std::make_pair(symbolName, AsmSymbol()));
1187    if (!res.second && ((res.first->second.onceDefined || !reassign) &&
1188        res.first->second.isDefined()))
1189    {   // found and can be only once defined
1190        printError(symbolPlace, (std::string("Symbol '") + symbolName.c_str() +
1191                    "' is already defined").c_str());
1192        return false;
1193    }
1194    AsmSymbolEntry& symEntry = *res.first;
1195   
1196    if (expr->getSymOccursNum()==0)
1197    {   // can evalute, assign now
1198        uint64_t value;
1199        cxuint sectionId;
1200        if (!expr->evaluate(*this, value, sectionId))
1201            return false;
1202       
1203        setSymbol(symEntry, value, sectionId);
1204        symEntry.second.onceDefined = !reassign;
1205    }
1206    else // set expression
1207    {
1208        expr->setTarget(AsmExprTarget::symbolTarget(&symEntry));
1209        symEntry.second.expression = expr.release();
1210        symEntry.second.regRange = symEntry.second.hasValue = false;
1211        symEntry.second.onceDefined = !reassign;
1212        symEntry.second.base = baseExpr;
1213        if (baseExpr && !symEntry.second.occurrencesInExprs.empty())
1214        {   /* make snapshot now resolving dependencies */
1215            AsmSymbolEntry* tempSymEntry;
1216            if (!AsmExpression::makeSymbolSnapshot(*this, symEntry, tempSymEntry,
1217                    &symEntry.second.occurrencesInExprs[0].expression->getSourcePos()))
1218                return false;
1219            tempSymEntry->second.occurrencesInExprs =
1220                        symEntry.second.occurrencesInExprs;
1221            // clear occurrences after copy
1222            symEntry.second.occurrencesInExprs.clear();
1223            if (tempSymEntry->second.hasValue) // set symbol chain
1224                setSymbol(*tempSymEntry, tempSymEntry->second.value,
1225                          tempSymEntry->second.sectionId);
1226        }
1227    }
1228    return true;
1229}
1230
1231bool Assembler::assignOutputCounter(const char* symbolPlace, uint64_t value,
1232            cxuint sectionId, cxbyte fillValue)
1233{
1234    initializeOutputFormat();
1235    if (currentSection != sectionId && sectionId != ASMSECT_ABS)
1236    {
1237        printError(symbolPlace, "Illegal section change for symbol '.'");
1238        return false;
1239    }
1240    if (currentSection != ASMSECT_ABS && int64_t(currentOutPos) > int64_t(value))
1241    {   /* check attempt to move backwards only for section that is not absolute */
1242        printError(symbolPlace, "Attempt to move backwards");
1243        return false;
1244    }
1245    if (!isAddressableSection())
1246    {
1247        printError(symbolPlace,
1248                   "Change output counter inside non-addressable section is illegal");
1249        return false;
1250    }
1251    if (currentSection==ASMSECT_ABS && fillValue!=0)
1252        printWarning(symbolPlace, "Fill value is ignored inside absolute section");
1253    if (value-currentOutPos!=0)
1254        reserveData(value-currentOutPos, fillValue);
1255    currentOutPos = value;
1256    return true;
1257}
1258
1259bool Assembler::skipSymbol(const char*& linePtr)
1260{
1261    const char* end = line+lineSize;
1262    skipSpacesToEnd(linePtr, end);
1263    const char* start = linePtr;
1264    if (linePtr != end)
1265    {   /* skip only symbol name */
1266        if(isAlpha(*linePtr) || *linePtr == '_' || *linePtr == '.' || *linePtr == '$')
1267            for (linePtr++; linePtr != end && (isAlnum(*linePtr) || *linePtr == '_' ||
1268                 *linePtr == '.' || *linePtr == '$') ; linePtr++);
1269    }
1270    if (start == linePtr)
1271    {   // this is not symbol name
1272        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
1273        printError(start, "Expected symbol name");
1274        return false;
1275    }
1276    return true;
1277}
1278
1279bool Assembler::isAbsoluteSymbol(const AsmSymbol& symbol) const
1280{
1281    if (symbol.sectionId == ASMSECT_ABS)
1282        return true;
1283    // otherwise check section
1284    if (sections.empty())
1285        return false; // fallback
1286    const AsmSection& section = sections[symbol.sectionId];
1287    return (section.flags&ASMSECT_ABS_ADDRESSABLE) != 0;
1288}
1289
1290void Assembler::printWarning(const AsmSourcePos& pos, const char* message)
1291{
1292    if ((flags & ASM_WARNINGS) == 0)
1293        return; // do nothing
1294    pos.print(messageStream);
1295    messageStream.write(": Warning: ", 11);
1296    messageStream.write(message, ::strlen(message));
1297    messageStream.put('\n');
1298}
1299
1300void Assembler::printError(const AsmSourcePos& pos, const char* message)
1301{
1302    good = false;
1303    pos.print(messageStream);
1304    messageStream.write(": Error: ", 9);
1305    messageStream.write(message, ::strlen(message));
1306    messageStream.put('\n');
1307}
1308
1309void Assembler::printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
1310        cxbyte signess)
1311{
1312    if (bits < 64)
1313    {   /* signess - WS_BOTH - check value range as signed value
1314         * WS_UNSIGNED - check value as unsigned value */
1315        if (signess == WS_BOTH &&
1316            !(int64_t(value) >= (1LL<<bits) || int64_t(value) < -(1LL<<(bits-1))))
1317            return;
1318        if (signess == WS_UNSIGNED && (value < (1ULL<<bits)))
1319            return;
1320        std::string warning = "Value ";
1321        char buf[32];
1322        itocstrCStyle(value, buf, 32, 16);
1323        warning += buf;
1324        warning += " truncated to ";
1325        itocstrCStyle(value&((1ULL<<bits)-1), buf, 32, 16);
1326        warning += buf;
1327        printWarning(pos, warning.c_str());
1328    }
1329}
1330
1331bool Assembler::checkReservedName(const CString& name)
1332{
1333    return false;
1334}
1335
1336void Assembler::addIncludeDir(const CString& includeDir)
1337{
1338    includeDirs.push_back(includeDir);
1339}
1340
1341void Assembler::addInitialDefSym(const CString& symName, uint64_t value)
1342{
1343    defSyms.push_back({symName, value});
1344}
1345
1346bool Assembler::pushClause(const char* string, AsmClauseType clauseType, bool satisfied,
1347               bool& included)
1348{
1349    if (clauseType == AsmClauseType::MACRO || clauseType == AsmClauseType::IF ||
1350        clauseType == AsmClauseType::REPEAT)
1351    {   // add new clause
1352        clauses.push({ clauseType, getSourcePos(string), satisfied, { } });
1353        included = satisfied;
1354        return true;
1355    }
1356    if (clauses.empty())
1357    {   // no clauses
1358        if (clauseType == AsmClauseType::ELSEIF)
1359            printError(string, "No '.if' before '.elseif");
1360        else // else
1361            printError(string, "No '.if' before '.else'");
1362        return false;
1363    }
1364    AsmClause& clause = clauses.top();
1365    switch(clause.type)
1366    {
1367        case AsmClauseType::ELSE:
1368            if (clauseType == AsmClauseType::ELSEIF)
1369                printError(string, "'.elseif' after '.else'");
1370            else // else
1371                printError(string, "Duplicate of '.else'");
1372            printError(clause.sourcePos, "here is previous '.else'"); 
1373            printError(clause.prevIfPos, "here is begin of conditional clause"); 
1374            return false;
1375        case AsmClauseType::MACRO:
1376            if (clauseType == AsmClauseType::ELSEIF)
1377                printError(string,
1378                       "No '.if' before '.elseif' inside macro");
1379            else // else
1380                printError(string,
1381                       "No '.if' before '.else' inside macro");
1382            return false;
1383        case AsmClauseType::REPEAT:
1384            if (clauseType == AsmClauseType::ELSEIF)
1385                printError(string,
1386                       "No '.if' before '.elseif' inside repetition");
1387            else // else
1388                printError(string,
1389                       "No '.if' before '.else' inside repetition");
1390            return false;
1391        default:
1392            break;
1393    }
1394    included = satisfied && !clause.condSatisfied;
1395    clause.condSatisfied |= included;
1396    if (clause.type == AsmClauseType::IF)
1397        clause.prevIfPos = clause.sourcePos;
1398    clause.type = clauseType;
1399    clause.sourcePos = getSourcePos(string);
1400    return true;
1401}
1402
1403bool Assembler::popClause(const char* string, AsmClauseType clauseType)
1404{
1405    if (clauses.empty())
1406    {   // no clauses
1407        if (clauseType == AsmClauseType::IF)
1408            printError(string, "No conditional before '.endif'");
1409        else if (clauseType == AsmClauseType::MACRO) // macro
1410            printError(string, "No '.macro' before '.endm'");
1411        else if (clauseType == AsmClauseType::REPEAT) // repeat
1412            printError(string, "No '.rept' before '.endr'");
1413        return false;
1414    }
1415    AsmClause& clause = clauses.top();
1416    switch(clause.type)
1417    {
1418        case AsmClauseType::IF:
1419        case AsmClauseType::ELSE:
1420        case AsmClauseType::ELSEIF:
1421            if (clauseType == AsmClauseType::MACRO)
1422            {
1423                printError(string, "Ending macro across conditionals");
1424                return false;
1425            }
1426            else if (clauseType == AsmClauseType::REPEAT)
1427            {
1428                printError(string, "Ending repetition across conditionals");
1429                return false;
1430            }
1431            break;
1432        case AsmClauseType::MACRO:
1433            if (clauseType == AsmClauseType::REPEAT)
1434            {
1435                printError(string, "Ending repetition across macro");
1436                return false;
1437            }
1438            if (clauseType == AsmClauseType::IF)
1439            {
1440                printError(string, "Ending conditional across macro");
1441                return false;
1442            }
1443            break;
1444        case AsmClauseType::REPEAT:
1445            if (clauseType == AsmClauseType::MACRO)
1446            {
1447                printError(string, "Ending macro across repetition");
1448                return false;
1449            }
1450            if (clauseType == AsmClauseType::IF)
1451            {
1452                printError(string, "Ending conditional across repetition");
1453                return false;
1454            }
1455            break;
1456        default:
1457            break;
1458    }
1459    clauses.pop();
1460    return true;
1461}
1462
1463Assembler::ParseState Assembler::makeMacroSubstitution(const char* linePtr)
1464{
1465    const char* end = line+lineSize;
1466    const char* macroStartPlace = linePtr;
1467   
1468    CString macroName = extractSymName(linePtr, end, false);
1469    if (macroName.empty())
1470        return ParseState::MISSING;
1471    toLowerString(macroName);
1472    MacroMap::const_iterator it = macroMap.find(macroName);
1473    if (it == macroMap.end())
1474        return ParseState::MISSING; // macro not found
1475   
1476    /* parse arguments */
1477    RefPtr<const AsmMacro> macro = it->second;
1478    const size_t macroArgsNum = macro->getArgsNum();
1479    bool good = true;
1480    AsmMacroInputFilter::MacroArgMap argMap(macroArgsNum);
1481    for (size_t i = 0; i < macroArgsNum; i++) // set name of args
1482        argMap[i].first = macro->getArg(i).name;
1483   
1484    for (size_t i = 0; i < macroArgsNum; i++)
1485    {
1486        const AsmMacroArg& arg = macro->getArg(i);
1487       
1488        skipSpacesToEnd(linePtr, end);
1489        if (linePtr!=end && *linePtr==',' && i!=0)
1490            skipCharAndSpacesToEnd(linePtr, end);
1491       
1492        std::string macroArg;
1493        const char* argPlace = linePtr;
1494        if (!arg.vararg)
1495        {
1496            if (!parseMacroArgValue(linePtr, macroArg))
1497            {
1498                good = false;
1499                continue;
1500            }
1501        }
1502        else
1503        {   /* parse variadic arguments, they requires ',' separator */
1504            bool argGood = true;
1505            while (linePtr != end)
1506            {
1507                if (!parseMacroArgValue(linePtr, macroArg))
1508                {
1509                    argGood = good = false;
1510                    break;
1511                }
1512                skipSpacesToEnd(linePtr, end);
1513                if (linePtr!=end)
1514                {
1515                    if(*linePtr==',')
1516                    {
1517                        skipCharAndSpacesToEnd(linePtr, end);
1518                        macroArg.push_back(',');
1519                    }
1520                    else
1521                    {
1522                        printError(linePtr, "Garbages at end of line");
1523                        argGood = good = false;
1524                        break;
1525                    }
1526                }
1527            }
1528            if (!argGood) // not so good
1529                continue;
1530        }
1531        argMap[i].second = macroArg;
1532        if (arg.required && argMap[i].second.empty())
1533        {   // error, value required
1534            printError(argPlace, (std::string("Value required for macro argument '") +
1535                    arg.name.c_str() + '\'').c_str());
1536            good = false;
1537        }
1538        else if (argMap[i].second.empty())
1539            argMap[i].second = arg.defaultValue;
1540    }
1541   
1542    skipSpacesToEnd(linePtr, end);
1543    if (!good)
1544        return ParseState::FAILED;
1545    if (linePtr != end)
1546    {
1547        printError(linePtr, "Garbages at end of line");
1548        return ParseState::FAILED;
1549    }
1550   
1551    if (macroSubstLevel == 1000)
1552    {
1553        printError(macroStartPlace, "Macro substitution level is greater than 1000");
1554        return ParseState::FAILED;
1555    }
1556    // sort argmap before using
1557    mapSort(argMap.begin(), argMap.end());
1558    // create macro input filter and push to stack
1559    std::unique_ptr<AsmInputFilter> macroFilter(new AsmMacroInputFilter(macro,
1560            getSourcePos(macroStartPlace), std::move(argMap), macroCount++,
1561            alternateMacro));
1562    asmInputFilters.push(macroFilter.release());
1563    currentInputFilter = asmInputFilters.top();
1564    macroSubstLevel++;
1565    return ParseState::PARSED;
1566}
1567
1568bool Assembler::includeFile(const char* pseudoOpPlace, const std::string& filename)
1569{
1570    if (inclusionLevel == 500)
1571    {
1572        printError(pseudoOpPlace, "Inclusion level is greater than 500");
1573        return false;
1574    }
1575    std::unique_ptr<AsmInputFilter> newInputFilter(new AsmStreamInputFilter(
1576                getSourcePos(pseudoOpPlace), filename));
1577    asmInputFilters.push(newInputFilter.release());
1578    currentInputFilter = asmInputFilters.top();
1579    inclusionLevel++;
1580    return true;
1581}
1582
1583bool Assembler::readLine()
1584{
1585    line = currentInputFilter->readLine(*this, lineSize);
1586    while (line == nullptr)
1587    {   // no line
1588        if (asmInputFilters.size() > 1)
1589        {   /* decrease some level of a nesting */
1590            if (currentInputFilter->getType() == AsmInputFilterType::MACROSUBST)
1591                macroSubstLevel--;
1592            else if (currentInputFilter->getType() == AsmInputFilterType::STREAM)
1593                inclusionLevel--;
1594            else if (currentInputFilter->getType() == AsmInputFilterType::REPEAT)
1595                repetitionLevel--;
1596            delete asmInputFilters.top();
1597            asmInputFilters.pop();
1598        }
1599        else if (filenameIndex<filenames.size())
1600        {   /* handling input assembler that have many files */
1601            do { // delete previous filter
1602                delete asmInputFilters.top();
1603                asmInputFilters.pop();
1604                /// create new input filter
1605                std::unique_ptr<AsmStreamInputFilter> thatFilter(
1606                    new AsmStreamInputFilter(filenames[filenameIndex++]));
1607                asmInputFilters.push(thatFilter.get());
1608                currentInputFilter = thatFilter.release();
1609                line = currentInputFilter->readLine(*this, lineSize);
1610            } while (line==nullptr && filenameIndex<filenames.size());
1611           
1612            return (line!=nullptr);
1613        }
1614        else
1615            return false;
1616        currentInputFilter = asmInputFilters.top();
1617        line = currentInputFilter->readLine(*this, lineSize);
1618    }
1619    return true;
1620}
1621
1622cxbyte* Assembler::reserveData(size_t size, cxbyte fillValue)
1623{
1624    if (currentSection != ASMSECT_ABS)
1625    {
1626        size_t oldOutPos = currentOutPos;
1627        AsmSection& section = sections[currentSection];
1628        if ((section.flags & ASMSECT_WRITEABLE) == 0) // non writeable
1629        {
1630            currentOutPos += size;
1631            section.size += size;
1632            return nullptr;
1633        }
1634        else
1635        {
1636            section.content.insert(section.content.end(), size, fillValue);
1637            currentOutPos += size;
1638            return section.content.data() + oldOutPos;
1639        }
1640    }
1641    else
1642    {
1643        currentOutPos += size;
1644        return nullptr;
1645    }
1646}
1647
1648
1649void Assembler::goToMain(const char* pseudoOpPlace)
1650{
1651    try
1652    { formatHandler->setCurrentKernel(ASMKERN_GLOBAL); }
1653    catch(const AsmFormatException& ex) // if error
1654    { printError(pseudoOpPlace, ex.what()); }
1655   
1656    currentOutPos = sections[currentSection].getSize();
1657}
1658
1659void Assembler::goToKernel(const char* pseudoOpPlace, const char* kernelName)
1660{
1661    auto kmit = kernelMap.find(kernelName);
1662    if (kmit == kernelMap.end())
1663    {   // not found, add new kernel
1664        cxuint kernelId;
1665        try
1666        { kernelId = formatHandler->addKernel(kernelName); }
1667        catch(const AsmFormatException& ex)
1668        {   // error!
1669            printError(pseudoOpPlace, ex.what());
1670            return;
1671        }
1672        // add new kernel entries and section entry
1673        auto it = kernelMap.insert(std::make_pair(kernelName, kernelId)).first;
1674        kernels.push_back({ it->first.c_str(),  getSourcePos(pseudoOpPlace) });
1675        auto info = formatHandler->getSectionInfo(currentSection);
1676        sections.push_back({ info.name, currentKernel, info.type, info.flags, 0 });
1677        currentOutPos = 0;
1678    }
1679    else
1680    {   // found
1681        try
1682        { formatHandler->setCurrentKernel(kmit->second); }
1683        catch(const AsmFormatException& ex) // if error
1684        {
1685            printError(pseudoOpPlace, ex.what());
1686            return;
1687        }
1688       
1689        currentOutPos = sections[currentSection].getSize();
1690    }
1691}
1692
1693void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
1694                            uint64_t align)
1695{
1696    const cxuint sectionId = formatHandler->getSectionId(sectionName);
1697    if (sectionId == ASMSECT_NONE)
1698    {   // try to add new section
1699        cxuint sectionId;
1700        try
1701        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
1702        catch(const AsmFormatException& ex)
1703        {   // error!
1704            printError(pseudoOpPlace, ex.what());
1705            return;
1706        }
1707        auto info = formatHandler->getSectionInfo(sectionId);
1708        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1709        currentOutPos = 0;
1710    }
1711    else // if section exists
1712    {   // found, try to set
1713        try
1714        { formatHandler->setCurrentSection(sectionId); }
1715        catch(const AsmFormatException& ex) // if error
1716        {
1717            printError(pseudoOpPlace, ex.what());
1718            return;
1719        }
1720       
1721        if (align!=0)
1722            printWarning(pseudoOpPlace, "Section alignment was ignored");
1723        currentOutPos = sections[currentSection].getSize();
1724    }
1725}
1726
1727void Assembler::goToSection(const char* pseudoOpPlace, const char* sectionName,
1728        AsmSectionType type, Flags flags, uint64_t align)
1729{
1730    const cxuint sectionId = formatHandler->getSectionId(sectionName);
1731    if (sectionId == ASMSECT_NONE)
1732    {   // try to add new section
1733        cxuint sectionId;
1734        try
1735        { sectionId = formatHandler->addSection(sectionName, currentKernel); }
1736        catch(const AsmFormatException& ex)
1737        {   // error!
1738            printError(pseudoOpPlace, ex.what());
1739            return;
1740        }
1741        auto info = formatHandler->getSectionInfo(sectionId);
1742        if (info.type == AsmSectionType::EXTRA_SECTION)
1743        {
1744            info.type = type;
1745            info.flags |= flags;
1746        }
1747        else
1748            printWarning(pseudoOpPlace,
1749                     "Section type and flags was ignored for builtin section");
1750        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1751        currentOutPos = 0;
1752    }
1753    else // if section exists
1754    {   // found, try to set
1755        try
1756        { formatHandler->setCurrentSection(sectionId); }
1757        catch(const AsmFormatException& ex) // if error
1758        {
1759            printError(pseudoOpPlace, ex.what());
1760            return;
1761        }
1762       
1763        printWarning(pseudoOpPlace, "Section type, flags and alignment was ignored");
1764        currentOutPos = sections[currentSection].getSize();
1765    }
1766}
1767
1768void Assembler::goToSection(const char* pseudoOpPlace, cxuint sectionId, uint64_t align)
1769{
1770    try
1771    { formatHandler->setCurrentSection(sectionId); }
1772    catch(const AsmFormatException& ex) // if error
1773    { printError(pseudoOpPlace, ex.what()); }
1774    if (sectionId >= sections.size())
1775    {
1776        auto info = formatHandler->getSectionInfo(sectionId);
1777        sections.push_back({ info.name, currentKernel, info.type, info.flags, align });
1778    }
1779    else if (align!=0)
1780        printWarning(pseudoOpPlace, "Section alignment was ignored");
1781   
1782    currentOutPos = sections[currentSection].getSize();
1783}
1784
1785void Assembler::initializeOutputFormat()
1786{
1787    if (formatHandler!=nullptr)
1788        return;
1789    switch(format)
1790    {
1791        case BinaryFormat::AMD:
1792            formatHandler = new AsmAmdHandler(*this);
1793            break;
1794        case BinaryFormat::AMDCL2:
1795            formatHandler = new AsmAmdCL2Handler(*this);
1796            break;
1797        case BinaryFormat::GALLIUM:
1798            formatHandler = new AsmGalliumHandler(*this);
1799            break;
1800        case BinaryFormat::ROCM:
1801            //formatHandler = new AsmROCmHandler(*this);
1802            break;
1803        default:
1804            formatHandler = new AsmRawCodeHandler(*this);
1805            break;
1806    }
1807    isaAssembler = new GCNAssembler(*this);
1808    // add first section
1809    auto info = formatHandler->getSectionInfo(currentSection);
1810    sections.push_back({ info.name, currentKernel, info.type, info.flags, 0 });
1811    currentOutPos = 0;
1812}
1813
1814bool Assembler::assemble()
1815{
1816    resolvingRelocs = false;
1817   
1818    for (const DefSym& defSym: defSyms)
1819        if (defSym.first!=".")
1820            symbolMap[defSym.first] = AsmSymbol(ASMSECT_ABS, defSym.second);
1821        else if ((flags & ASM_WARNINGS) != 0)// ignore for '.'
1822            messageStream << "<command-line>: Warning: Definition for symbol '.' "
1823                    "was ignored" << std::endl;
1824   
1825    good = true;
1826    while (!endOfAssembly)
1827    {
1828        if (!lineAlreadyRead)
1829        {   // read line
1830            if (!readLine())
1831                break;
1832        }
1833        else
1834        {   // already line is read
1835            lineAlreadyRead = false;
1836            if (line == nullptr)
1837                break; // end of stream
1838        }
1839       
1840        const char* linePtr = line; // string points to place of line
1841        const char* end = line+lineSize;
1842        skipSpacesToEnd(linePtr, end);
1843        if (linePtr == end)
1844            continue; // only empty line
1845       
1846        // statement start (except labels). in this time can point to labels
1847        const char* stmtPlace = linePtr;
1848        CString firstName = extractLabelName(linePtr, end);
1849       
1850        skipSpacesToEnd(linePtr, end);
1851       
1852        bool doNextLine = false;
1853        while (!firstName.empty() && linePtr != end && *linePtr == ':')
1854        {   // labels
1855            linePtr++;
1856            skipSpacesToEnd(linePtr, end);
1857            initializeOutputFormat();
1858            if (firstName.front() >= '0' && firstName.front() <= '9')
1859            {   // handle local labels
1860                if (sections.empty())
1861                {
1862                    printError(stmtPlace, "Local label can't be defined outside section");
1863                    doNextLine = true;
1864                    break;
1865                }
1866                if (!isAddressableSection())
1867                {
1868                    printError(stmtPlace, "Local label can't be defined in "
1869                            "non-addressable section ");
1870                    doNextLine = true;
1871                    break;
1872                }
1873                /* prevLRes - iterator to previous instance of local label (with 'b)
1874                 * nextLRes - iterator to next instance of local label (with 'f) */
1875                std::pair<AsmSymbolMap::iterator, bool> prevLRes =
1876                        symbolMap.insert(std::make_pair(
1877                            std::string(firstName.c_str())+"b", AsmSymbol()));
1878                std::pair<AsmSymbolMap::iterator, bool> nextLRes =
1879                        symbolMap.insert(std::make_pair(
1880                            std::string(firstName.c_str())+"f", AsmSymbol()));
1881                /* resolve forward symbol of label now */
1882                assert(setSymbol(*nextLRes.first, currentOutPos, currentSection));
1883                // move symbol value from next local label into previous local label
1884                // clearOccurrences - obsolete - back local labels are undefined!
1885                prevLRes.first->second.value = nextLRes.first->second.value;
1886                prevLRes.first->second.hasValue = isResolvableSection();
1887                prevLRes.first->second.sectionId = currentSection;
1888                /// make forward symbol of label as undefined
1889                nextLRes.first->second.hasValue = false;
1890            }
1891            else
1892            {   // regular labels
1893                std::pair<AsmSymbolMap::iterator, bool> res = 
1894                        symbolMap.insert(std::make_pair(firstName, AsmSymbol()));
1895                if (!res.second)
1896                {   // found
1897                    if (res.first->second.onceDefined && res.first->second.isDefined())
1898                    {   // if label
1899                        printError(stmtPlace, (std::string("Symbol '")+firstName.c_str()+
1900                                    "' is already defined").c_str());
1901                        doNextLine = true;
1902                        break;
1903                    }
1904                }
1905                if (sections.empty())
1906                {
1907                    printError(stmtPlace,
1908                               "Label can't be defined outside section");
1909                    doNextLine = true;
1910                    break;
1911                }
1912                if (!isAddressableSection())
1913                {
1914                    printError(stmtPlace, "Label can't be defined in "
1915                            "non-addressable section ");
1916                    doNextLine = true;
1917                    break;
1918                }
1919               
1920                setSymbol(*res.first, currentOutPos, currentSection);
1921                res.first->second.onceDefined = true;
1922                res.first->second.sectionId = currentSection;
1923               
1924                formatHandler->handleLabel(res.first->first);
1925            }
1926            // new label or statement
1927            stmtPlace = linePtr;
1928            firstName = extractLabelName(linePtr, end);
1929        }
1930        if (doNextLine)
1931            continue;
1932       
1933        /* now stmtStartStr - points to first string of statement
1934         * (labels has been skipped) */
1935        skipSpacesToEnd(linePtr, end);
1936        if (linePtr != end && *linePtr == '=' &&
1937            // not for local labels
1938            !isDigit(firstName.front()))
1939        {   // assignment
1940            skipCharAndSpacesToEnd(linePtr, line+lineSize);
1941            if (linePtr == end)
1942            {
1943                printError(linePtr, "Expected assignment expression");
1944                continue;
1945            }
1946            assignSymbol(firstName, stmtPlace, linePtr);
1947            continue;
1948        }
1949        // make firstname as lowercase
1950        toLowerString(firstName);
1951       
1952        if (firstName.size() >= 2 && firstName[0] == '.') // check for pseudo-op
1953            parsePseudoOps(firstName, stmtPlace, linePtr);
1954        else if (firstName.size() >= 1 && isDigit(firstName[0]))
1955            printError(stmtPlace, "Illegal number at statement begin");
1956        else
1957        {   // try to parse processor instruction or macro substitution
1958            if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
1959            { 
1960                if (firstName.empty()) // if name is empty
1961                {
1962                    if (linePtr!=end) // error
1963                        printError(stmtPlace, "Garbages at statement place");
1964                    continue;
1965                }
1966                initializeOutputFormat();
1967                // try parse instruction
1968                if (!isWriteableSection())
1969                {
1970                    printError(stmtPlace,
1971                       "Writing data into non-writeable section is illegal");
1972                    continue;
1973                }
1974                isaAssembler->assemble(firstName, stmtPlace, linePtr, end,
1975                           sections[currentSection].content);
1976                currentOutPos = sections[currentSection].getSize();
1977            }
1978        }
1979    }
1980    /* check clauses and print errors */
1981    while (!clauses.empty())
1982    {
1983        const AsmClause& clause = clauses.top();
1984        switch(clause.type)
1985        {
1986            case AsmClauseType::IF:
1987                printError(clause.sourcePos, "Unterminated '.if'");
1988                break;
1989            case AsmClauseType::ELSEIF:
1990                printError(clause.sourcePos, "Unterminated '.elseif'");
1991                printError(clause.prevIfPos, "here is begin of conditional clause"); 
1992                break;
1993            case AsmClauseType::ELSE:
1994                printError(clause.sourcePos, "Unterminated '.else'");
1995                printError(clause.prevIfPos, "here is begin of conditional clause"); 
1996                break;
1997            case AsmClauseType::MACRO:
1998                printError(clause.sourcePos, "Unterminated macro definition");
1999                break;
2000            case AsmClauseType::REPEAT:
2001                printError(clause.sourcePos, "Unterminated repetition");
2002            default:
2003                break;
2004        }
2005        clauses.pop();
2006    }
2007   
2008    resolvingRelocs = true;
2009    for (AsmSymbolEntry& symEntry: symbolMap)
2010        if (!symEntry.second.occurrencesInExprs.empty() || 
2011            (symEntry.first!="."  && !isResolvableSection(symEntry.second.sectionId)))
2012        {   // try to resolve symbols
2013            uint64_t value;
2014            cxuint sectionId;
2015            if (formatHandler!=nullptr &&
2016                formatHandler->resolveSymbol(symEntry.second, value, sectionId))
2017                setSymbol(symEntry, value, sectionId);
2018        }
2019   
2020    if ((flags&ASM_TESTRUN) == 0)
2021        for (AsmSymbolEntry& symEntry: symbolMap)
2022            if (!symEntry.second.occurrencesInExprs.empty())
2023                for (AsmExprSymbolOccurrence occur: symEntry.second.occurrencesInExprs)
2024                    printError(occur.expression->getSourcePos(),(std::string(
2025                        "Unresolved symbol '")+symEntry.first.c_str()+"'").c_str());
2026   
2027    if (good && formatHandler!=nullptr)
2028        formatHandler->prepareBinary();
2029    return good;
2030}
2031
2032void Assembler::writeBinary(const char* filename) const
2033{
2034    if (good)
2035    {
2036        const AsmFormatHandler* formatHandler = getFormatHandler();
2037        if (formatHandler!=nullptr)
2038        {
2039            std::ofstream ofs(filename, std::ios::binary);
2040            if (ofs)
2041                formatHandler->writeBinary(ofs);
2042            else
2043                throw Exception(std::string("Can't open output file '")+filename+"'");
2044        }
2045        else
2046            throw Exception("No output binary");
2047    }
2048    else // failed
2049        throw Exception("Assembler failed!");
2050}
2051
2052void Assembler::writeBinary(std::ostream& outStream) const
2053{
2054    if (good)
2055    {
2056        const AsmFormatHandler* formatHandler = getFormatHandler();
2057        if (formatHandler!=nullptr)
2058            formatHandler->writeBinary(outStream);
2059        else
2060            throw Exception("No output binary");
2061    }
2062    else // failed
2063        throw Exception("Assembler failed!");
2064}
2065
2066void Assembler::writeBinary(Array<cxbyte>& array) const
2067{
2068    if (good)
2069    {
2070        const AsmFormatHandler* formatHandler = getFormatHandler();
2071        if (formatHandler!=nullptr)
2072            formatHandler->writeBinary(array);
2073        else
2074            throw Exception("No output binary");
2075    }
2076    else // failed
2077        throw Exception("Assembler failed!");
2078}
Note: See TracBrowser for help on using the repository browser.