Changeset 4136 in CLRX


Ignore:
Timestamp:
May 10, 2018, 3:38:43 PM (7 months ago)
Author:
matszpk
Message:

CLRadeonExtender: Asm: Move pseudo-ops code to separate source code.

Location:
CLRadeonExtender/trunk/amdasm
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • CLRadeonExtender/trunk/amdasm/AsmPseudoOps.cpp

    r4133 r4136  
    2020#include <CLRX/Config.h>
    2121#include <string>
    22 #include <cstring>
    23 #include <cassert>
    2422#include <fstream>
    25 #include <vector>
    2623#include <utility>
    27 #include <algorithm>
    2824#include <CLRX/utils/Utilities.h>
    29 #include <CLRX/amdbin/AmdBinaries.h>
    30 #include <CLRX/amdbin/GalliumBinaries.h>
    31 #include <CLRX/utils/MemAccess.h>
    32 #include <CLRX/utils/GPUId.h>
    3325#include <CLRX/utils/InputOutput.h>
    3426#include <CLRX/amdasm/Assembler.h>
     
    179171{
    180172
    181 void AsmPseudoOps::setBitness(Assembler& asmr, const char* linePtr, bool _64Bit)
    182 {
    183     if (!checkGarbagesAtEnd(asmr, linePtr))
    184         return;
    185     if (asmr.formatHandler != nullptr)
    186         asmr.printError(linePtr, "Bitness is already defined");
    187     else if (asmr.format == BinaryFormat::ROCM)
    188     {
    189         // ROCm is always 64-bit, print warning about it
    190         if (!_64Bit)
    191             asmr.printWarning(linePtr, "For ROCm bitness is always 64bit");
    192     }
    193     else if (asmr.format != BinaryFormat::AMD && asmr.format != BinaryFormat::GALLIUM &&
    194         asmr.format != BinaryFormat::AMDCL2)
    195         // print warning (for raw format) that bitness is ignored
    196         asmr.printWarning(linePtr, "Bitness ignored for other formats than "
    197                 "AMD Catalyst, ROCm and GalliumCompute");
    198     else
    199         asmr._64bit = (_64Bit);
    200 }
    201 
    202 bool AsmPseudoOps::parseFormat(Assembler& asmr, const char*& linePtr, BinaryFormat& format)
    203 {
    204     const char* end = asmr.line + asmr.lineSize;
    205     skipSpacesToEnd(linePtr, end);
    206     const char* formatPlace = linePtr;
    207     char formatName[10];
    208     if (!getNameArg(asmr, 10, formatName, linePtr, "output format type"))
    209         return false;
    210    
    211     toLowerString(formatName);
    212     // choose correct binary format
    213     if (::strcmp(formatName, "catalyst")==0 || ::strcmp(formatName, "amd")==0)
    214         format = BinaryFormat::AMD;
    215     else if (::strcmp(formatName, "amdcl2")==0)
    216         format = BinaryFormat::AMDCL2;
    217     else if (::strcmp(formatName, "gallium")==0)
    218         format = BinaryFormat::GALLIUM;
    219     else if (::strcmp(formatName, "rocm")==0)
    220         format = BinaryFormat::ROCM;
    221     else if (::strcmp(formatName, "raw")==0)
    222         format = BinaryFormat::RAWCODE;
    223     else
    224         ASM_FAIL_BY_ERROR(formatPlace, "Unknown output format type")
    225     return true;
    226 }
    227 
    228 // .format pseudo-op
    229 void AsmPseudoOps::setOutFormat(Assembler& asmr, const char* linePtr)
    230 {
    231     const char* end = asmr.line + asmr.lineSize;
    232     BinaryFormat format;
    233     skipSpacesToEnd(linePtr, end);
    234     const char* formatPlace = linePtr;
    235     if (!parseFormat(asmr, linePtr, format))
    236         return;
    237    
    238     if (checkGarbagesAtEnd(asmr, linePtr))
    239     {
    240         // set if no garbages at end
    241         if (asmr.formatHandler!=nullptr)
    242             ASM_RETURN_BY_ERROR(formatPlace, "Output format type is already defined")
    243         asmr.format = format;
    244     }
    245 }
    246 
    247 void AsmPseudoOps::setGPUDevice(Assembler& asmr, const char* linePtr)
    248 {
    249     const char* end = asmr.line + asmr.lineSize;
    250     skipSpacesToEnd(linePtr, end);
    251     char deviceName[64];
    252     const char* deviceNamePlace = linePtr;
    253     if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
    254         return;
    255     try
    256     {
    257         GPUDeviceType deviceType = getGPUDeviceTypeFromName(deviceName);
    258         if (checkGarbagesAtEnd(asmr, linePtr))
    259             // set if no garbages at end
    260             asmr.deviceType = deviceType;
    261     }
    262     // if exception - print error
    263     catch(const Exception& ex)
    264     { asmr.printError(deviceNamePlace, ex.what()); }
    265 }
    266 
    267 void AsmPseudoOps::setGPUArchitecture(Assembler& asmr, const char* linePtr)
    268 {
    269     const char* end = asmr.line + asmr.lineSize;
    270     skipSpacesToEnd(linePtr, end);
    271     char deviceName[64];
    272     const char* archNamePlace = linePtr;
    273     if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
    274         return;
    275     try
    276     {
    277         GPUArchitecture arch = getGPUArchitectureFromName(deviceName);
    278         GPUDeviceType deviceType = getLowestGPUDeviceTypeFromArchitecture(arch);
    279         if (checkGarbagesAtEnd(asmr, linePtr))
    280             // set if no garbages at end
    281             asmr.deviceType = deviceType;
    282     }
    283     // if exception - print error
    284     catch(const Exception& ex)
    285     { asmr.printError(archNamePlace, ex.what()); }
    286 }
    287 
    288 void AsmPseudoOps::goToKernel(Assembler& asmr, const char* pseudoOpPlace,
    289                   const char* linePtr)
    290 {
    291     asmr.initializeOutputFormat();
    292     const char* end = asmr.line + asmr.lineSize;
    293     skipSpacesToEnd(linePtr, end);
    294     CString kernelName;
    295     if (!getNameArg(asmr, kernelName, linePtr, "kernel name"))
    296         return;
    297     if (!checkGarbagesAtEnd(asmr, linePtr))
    298         return;
    299    
    300     asmr.goToKernel(pseudoOpPlace, kernelName.c_str());
    301 }
    302 
    303 /// isPseudoOp - if true then name is pseudo-operation (we must convert to lower-case)
    304 /// if pseudo-op we just do not try to parse section flags
    305 void AsmPseudoOps::goToSection(Assembler& asmr, const char* pseudoOpPlace,
    306                    const char* linePtr, bool isPseudoOp)
    307 {
    308     asmr.initializeOutputFormat();
    309     const char* end = asmr.line + asmr.lineSize;
    310     skipSpacesToEnd(linePtr, end);
    311     CString sectionName;
    312     if (!getNameArg(asmr, sectionName, linePtr, "section name"))
    313         return;
    314     if (isPseudoOp)
    315         toLowerString(sectionName);
    316     bool haveFlags = false;
    317     uint32_t sectFlags = 0;
    318     AsmSectionType sectType = AsmSectionType::EXTRA_SECTION;
    319     uint64_t sectionAlign = 0;
    320     if (!isPseudoOp)
    321     {
    322         skipSpacesToEnd(linePtr, end);
    323         if (linePtr!=end && *linePtr==',')
    324         {
    325             haveFlags = true;
    326             linePtr++;
    327         }
    328     }
    329     bool good = true;
    330     if (haveFlags)
    331     {
    332         std::string flagsStr;
    333         skipSpacesToEnd(linePtr, end);
    334         const char* flagsStrPlace = linePtr;
    335         if (asmr.parseString(flagsStr, linePtr))
    336         {
    337             // parse section flags (a,x,w)
    338             bool flagsStrIsGood = true;
    339             for (const char c: flagsStr)
    340                 if (c=='a')
    341                     sectFlags |= ASMELFSECT_ALLOCATABLE;
    342                 else if (c=='x')
    343                     sectFlags |= ASMELFSECT_EXECUTABLE;
    344                 else if (c=='w')
    345                     sectFlags |= ASMELFSECT_WRITEABLE;
    346                 else if (flagsStrIsGood)
    347                     ASM_NOTGOOD_BY_ERROR1(flagsStrIsGood = good, flagsStrPlace,
    348                             "Only 'a', 'w', 'x' is accepted in flags string")
    349         }
    350         else
    351             good = false;
    352        
    353         bool haveComma;
    354         if (!skipComma(asmr, haveComma, linePtr))
    355             return;
    356         if (haveComma)
    357         {
    358             // section type
    359             char typeBuf[20];
    360             skipSpacesToEnd(linePtr, end);
    361             const char* typePlace = linePtr;
    362             if (linePtr+1<end && *linePtr=='@' && isAlpha(linePtr[1]))
    363             {
    364                 // parse section type (progbits, note, nobits)
    365                 linePtr++;
    366                 if (getNameArg(asmr, 20, typeBuf, linePtr, "section type"))
    367                 {
    368                     toLowerString(typeBuf);
    369                     if (::strcmp(typeBuf, "progbits")==0)
    370                         sectType = AsmSectionType::EXTRA_PROGBITS;
    371                     else if (::strcmp(typeBuf, "note")==0)
    372                         sectType = AsmSectionType::EXTRA_NOTE;
    373                     else if (::strcmp(typeBuf, "nobits")==0)
    374                         sectType = AsmSectionType::EXTRA_NOBITS;
    375                     else
    376                         ASM_NOTGOOD_BY_ERROR(typePlace, "Unknown section type")
    377                 }
    378                 else
    379                     good = false;
    380             }
    381             else
    382                 ASM_NOTGOOD_BY_ERROR(typePlace, "Section type was not preceded by '@'")
    383         }
    384     }
    385     // parse alignment
    386     skipSpacesToEnd(linePtr, end);
    387     if (linePtr+6<end && ::strncasecmp(linePtr, "align", 5)==0 && !isAlpha(linePtr[5]))
    388     {
    389         // if alignment
    390         linePtr+=5;
    391         skipSpacesToEnd(linePtr, end);
    392         if (linePtr!=end && *linePtr=='=')
    393         {
    394             skipCharAndSpacesToEnd(linePtr, end);
    395             const char* valuePtr = linePtr;
    396             if (getAbsoluteValueArg(asmr, sectionAlign, linePtr, true))
    397             {
    398                 if (sectionAlign!=0 && (1ULL<<(63-CLZ64(sectionAlign))) != sectionAlign)
    399                     ASM_NOTGOOD_BY_ERROR(valuePtr, "Alignment must be power of two or zero")
    400             }
    401             else
    402                 good = false;
    403         }
    404         else
    405             ASM_NOTGOOD_BY_ERROR(linePtr, "Expected '=' after 'align'")
    406     }
    407    
    408     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    409         return;
    410    
    411     if (!haveFlags)
    412         // if section flags and section type not supplied
    413         asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectionAlign);
    414     else
    415         asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectType, sectFlags,
    416                  sectionAlign);
    417 }
    418 
    419 void AsmPseudoOps::goToMain(Assembler& asmr, const char* pseudoOpPlace,
    420                    const char* linePtr)
    421 {
    422     asmr.initializeOutputFormat();
    423     const char* end = asmr.line + asmr.lineSize;
    424     skipSpacesToEnd(linePtr, end);
    425     if (!checkGarbagesAtEnd(asmr, linePtr))
    426         return;
    427    
    428     asmr.goToMain(pseudoOpPlace);
    429 }
    430 
    431 void AsmPseudoOps::includeFile(Assembler& asmr, const char* pseudoOpPlace,
    432                    const char* linePtr)
    433 {
    434     const char* end = asmr.line + asmr.lineSize;
    435     skipSpacesToEnd(linePtr, end);
    436     std::string filename, sysfilename;
    437     const char* namePlace = linePtr;
    438     if (asmr.parseString(filename, linePtr))
    439     {
    440         if (!checkGarbagesAtEnd(asmr, linePtr))
    441             return;
    442         sysfilename = filename;
    443         bool failedOpen = false;
    444         // convert path to system path (with system dir separators)
    445         filesystemPath(sysfilename);
    446         try
    447         {
    448             asmr.includeFile(pseudoOpPlace, sysfilename);
    449             return;
    450         }
    451         catch(const Exception& ex)
    452         { failedOpen = true; }
    453        
    454         // find in include paths
    455         for (const CString& incDir: asmr.includeDirs)
    456         {
    457             failedOpen = false;
    458             std::string incDirPath(incDir.c_str());
    459             // convert path to system path (with system dir separators)
    460             filesystemPath(incDirPath);
    461             try
    462             {
    463                 asmr.includeFile(pseudoOpPlace, joinPaths(
    464                             std::string(incDirPath.c_str()), sysfilename));
    465                 break;
    466             }
    467             catch(const Exception& ex)
    468             { failedOpen = true; }
    469         }
    470         // if not found
    471         if (failedOpen)
    472             asmr.printError(namePlace, (std::string("Include file '") + filename +
    473                     "' not found or unavailable in any directory").c_str());
    474     }
    475 }
    476 
    477 void AsmPseudoOps::includeBinFile(Assembler& asmr, const char* pseudoOpPlace,
    478                           const char* linePtr)
    479 {
    480     asmr.initializeOutputFormat();
    481     const char* end = asmr.line + asmr.lineSize;
    482    
    483     if (!asmr.isWriteableSection())
    484         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    485    
    486     skipSpacesToEnd(linePtr, end);
    487     std::string filename, sysfilename;
    488     const char* namePlace = linePtr;
    489     const char* offsetPlace = linePtr;
    490     const char* countPlace = linePtr;
    491     uint64_t offset = 0, count = INT64_MAX;
    492    
    493     bool good = asmr.parseString(filename, linePtr);
    494     bool haveComma;
    495    
    496     if (!skipComma(asmr, haveComma, linePtr))
    497         return;
    498     if (haveComma)
    499     {
    500         skipSpacesToEnd(linePtr, end);
    501         // parse offset argument
    502         offsetPlace = linePtr;
    503         if (getAbsoluteValueArg(asmr, offset, linePtr))
    504         {
    505             // offset must not be negative
    506             if (int64_t(offset) < 0)
    507                 ASM_NOTGOOD_BY_ERROR(offsetPlace, "Offset is negative!")
    508         }
    509         else
    510             good = false;
    511        
    512         if (!skipComma(asmr, haveComma, linePtr))
    513             return;
    514         if (haveComma)
    515         {
    516             skipSpacesToEnd(linePtr, end);
    517             countPlace = linePtr;
    518             // parse count argument
    519             good &= getAbsoluteValueArg(asmr, count, linePtr);
    520             if (int64_t(count) < 0)
    521                 ASM_NOTGOOD_BY_ERROR(countPlace, "Count bytes is negative!")
    522         }
    523     }
    524    
    525     if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // failed parsing
    526         return;
    527    
    528     if (count == 0)
    529     {
    530         asmr.printWarning(namePlace, "Number of bytes is zero, ignoring .incbin");
    531         return;
    532     }
    533    
    534     std::ifstream ifs;
    535     sysfilename = filename;
    536     filesystemPath(sysfilename);
    537     // try in this directory
    538     ifs.open(sysfilename.c_str(), std::ios::binary);
    539     if (!ifs)
    540     {
    541         // find in include paths
    542         for (const CString& incDir: asmr.includeDirs)
    543         {
    544             std::string incDirPath(incDir.c_str());
    545             filesystemPath(incDirPath);
    546             ifs.open(joinPaths(incDirPath.c_str(), sysfilename).c_str(), std::ios::binary);
    547             if (ifs)
    548                 break;
    549         }
    550     }
    551     if (!ifs)
    552         ASM_RETURN_BY_ERROR(namePlace, (std::string("Binary file '") + filename +
    553                     "' not found or unavailable in any directory").c_str())
    554     // exception for checking file seeking
    555     bool seekingIsWorking = true;
    556     ifs.exceptions(std::ios::badbit | std::ios::failbit); // exceptions
    557     try
    558     { ifs.seekg(0, std::ios::end); /* to end of file */ }
    559     catch(const std::exception& ex)
    560     {
    561         /* oh, no! this is not regular file */
    562         seekingIsWorking = false;
    563         ifs.clear();
    564     }
    565     ifs.exceptions(std::ios::badbit);  // exceptions for reading
    566     if (seekingIsWorking)
    567     {
    568         /* for regular files */
    569         const uint64_t size = ifs.tellg();
    570         if (size < offset)
    571             return; // do nothing
    572         // skip offset bytes
    573         ifs.seekg(offset, std::ios::beg);
    574         const uint64_t toRead = std::min(size-offset, count);
    575         char* output = reinterpret_cast<char*>(asmr.reserveData(toRead));
    576         // and just read directly to output
    577         ifs.read(output, toRead);
    578         if (ifs.gcount() != std::streamsize(toRead))
    579             ASM_RETURN_BY_ERROR(namePlace, "Can't read whole needed file content")
    580     }
    581     else
    582     {
    583         /* for sequential files, likes fifo */
    584         char tempBuf[256];
    585         /// first we skipping bytes given in offset
    586         for (uint64_t pos = 0; pos < offset; )
    587         {
    588             const size_t toRead = std::min(offset-pos, uint64_t(256));
    589             ifs.read(tempBuf, toRead);
    590             const uint64_t readed = ifs.gcount();
    591             pos += readed;
    592             if (readed < toRead)
    593                 break;
    594         }
    595         // read data from binary file
    596         for (uint64_t bytes = 0; bytes < count; )
    597         {
    598             const size_t toRead = std::min(uint64_t(256), count-bytes);
    599             ifs.read(tempBuf, toRead);
    600             const uint64_t readed = ifs.gcount();
    601             asmr.putData(readed, (cxbyte*)tempBuf);
    602             bytes += readed;
    603             if (readed < toRead)
    604                 break;
    605         }
    606     }
    607 }
    608 
    609 void AsmPseudoOps::doFail(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    610 {
    611     const char* end = asmr.line + asmr.lineSize;
    612     skipSpacesToEnd(linePtr, end);
    613     uint64_t value = 0;
    614     if (!getAbsoluteValueArg(asmr, value, linePtr, true))
    615         return;
    616     if (!checkGarbagesAtEnd(asmr, linePtr))
    617         return;
    618    
    619     char buf[50];
    620     ::memcpy(buf, ".fail ", 6);
    621     const size_t pos = 6+itocstrCStyle(int64_t(value), buf+6, 50-6);
    622     ::memcpy(buf+pos, " encountered", 13);
    623     if (int64_t(value) >= 500)
    624         // value >=500 treat as error
    625         asmr.printWarning(pseudoOpPlace, buf);
    626     else
    627         asmr.printError(pseudoOpPlace, buf);
    628 }
    629 
    630 void AsmPseudoOps::doError(Assembler& asmr, const char* pseudoOpPlace,
    631                       const char* linePtr)
    632 {
    633     const char* end = asmr.line + asmr.lineSize;
    634     skipSpacesToEnd(linePtr, end);
    635     if (linePtr != end)
    636     {
    637         std::string outStr;
    638         if (!asmr.parseString(outStr, linePtr))
    639             return; // error
    640         if (!checkGarbagesAtEnd(asmr, linePtr))
    641             return;
    642         asmr.printError(pseudoOpPlace, outStr.c_str());
    643     }
    644     else
    645         // if without string
    646         asmr.printError(pseudoOpPlace, ".error encountered");
    647 }
    648 
    649 void AsmPseudoOps::doWarning(Assembler& asmr, const char* pseudoOpPlace,
    650                         const char* linePtr)
    651 {
    652     const char* end = asmr.line + asmr.lineSize;
    653     skipSpacesToEnd(linePtr, end);
    654     if (linePtr != end)
    655     {
    656         std::string outStr;
    657         if (!asmr.parseString(outStr, linePtr))
    658             return; // error
    659         if (!checkGarbagesAtEnd(asmr, linePtr))
    660             return;
    661         asmr.printWarning(pseudoOpPlace, outStr.c_str());
    662     }
    663     else
    664         // if without string
    665         asmr.printWarning(pseudoOpPlace, ".warning encountered");
    666 }
    667 
    668 template<typename T>
    669 void AsmPseudoOps::putIntegers(Assembler& asmr, const char* pseudoOpPlace,
    670                    const char* linePtr)
    671 {
    672     const char* end = asmr.line + asmr.lineSize;
    673     asmr.initializeOutputFormat();
    674     if (!asmr.isWriteableSection())
    675         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    676     skipSpacesToEnd(linePtr, end);
    677     if (linePtr == end)
    678         return;
    679     do {
    680         const char* exprPlace = linePtr;
    681         // try parse expression for this integer
    682         uint64_t value;
    683         if (AsmExpression::fastExprEvaluate(asmr, linePtr, value))
    684         {   // fast path (expression)
    685             if (sizeof(T) < 8)
    686                 asmr.printWarningForRange(sizeof(T)<<3, value,
    687                                 asmr.getSourcePos(exprPlace));
    688             T out;
    689             SLEV(out, value); // store in little-endian
    690             asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&out));
    691             continue;
    692         }
    693         std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr));
    694         if (expr)
    695         {
    696             if (expr->isEmpty()) // empty expression print warning
    697             {
    698                 asmr.printWarning(linePtr, "No expression, zero has been put");
    699                 uint64_t zero = 0;
    700                 asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&zero));
    701             }
    702             else if (expr->getSymOccursNum()==0)
    703             {
    704                 // put directly to section
    705                 cxuint sectionId;
    706                 AsmTryStatus  evalStatus = expr->tryEvaluate(asmr, value, sectionId,
    707                                         asmr.withSectionDiffs());
    708                 if (evalStatus == AsmTryStatus::SUCCESS)
    709                 {
    710                     if (sectionId == ASMSECT_ABS)
    711                     {
    712                         if (sizeof(T) < 8)
    713                             asmr.printWarningForRange(sizeof(T)<<3, value,
    714                                          asmr.getSourcePos(exprPlace));
    715                         T out;
    716                         SLEV(out, value); // store in little-endian
    717                         asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&out));
    718                     }
    719                     else
    720                         asmr.printError(exprPlace, "Expression must be absolute!");
    721                 }
    722                 else if (evalStatus == AsmTryStatus::TRY_LATER)
    723                 {
    724                     // if section diffs to resolve later
    725                     expr->setTarget(AsmExprTarget::dataTarget<T>(
    726                                     asmr.currentSection, asmr.currentOutPos));
    727                     asmr.unevalExpressions.push_back(expr.release());
    728                     asmr.reserveData(sizeof(T));
    729                 }
    730             }
    731             else // expression, we set target of expression (just data)
    732             {
    733                 /// will be resolved later
    734                 expr->setTarget(AsmExprTarget::dataTarget<T>(
    735                                 asmr.currentSection, asmr.currentOutPos));
    736                 expr.release();
    737                 asmr.reserveData(sizeof(T));
    738             }
    739         }
    740     } while(skipCommaForMultipleArgs(asmr, linePtr));
    741     checkGarbagesAtEnd(asmr, linePtr);
    742 }
    743 
    744 // helper for floating point parsing (with storing in little-endian)
    745 template<typename T> inline
    746 T asmcstrtofCStyleLEV(const char* str, const char* inend, const char*& outend);
    747 
    748 template<> inline
    749 uint16_t asmcstrtofCStyleLEV<uint16_t>(const char* str, const char* inend,
    750                    const char*& outend)
    751 { return LEV(cstrtohCStyle(str, inend, outend)); }
    752 
    753 template<> inline
    754 uint32_t asmcstrtofCStyleLEV<uint32_t>(const char* str, const char* inend,
    755                    const char*& outend)
    756 {
    757     union {
    758         float f;
    759         uint32_t u;
    760     } value;
    761     value.f = cstrtovCStyle<float>(str, inend, outend);
    762     return LEV(value.u);
    763 }
    764 
    765 template<> inline
    766 uint64_t asmcstrtofCStyleLEV<uint64_t>(const char* str, const char* inend,
    767                    const char*& outend)
    768 {
    769     union {
    770         double f;
    771         uint64_t u;
    772     } value;
    773     value.f = cstrtovCStyle<double>(str, inend, outend);
    774     return LEV(value.u);
    775 }
    776 
    777 template<typename UIntType>
    778 void AsmPseudoOps::putFloats(Assembler& asmr, const char* pseudoOpPlace,
    779                      const char* linePtr)
    780 {
    781     const char* end = asmr.line + asmr.lineSize;
    782     asmr.initializeOutputFormat();
    783     if (!asmr.isWriteableSection())
    784         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    785     skipSpacesToEnd(linePtr, end);
    786     if (linePtr == end)
    787         return;
    788     do {
    789         UIntType out = 0;
    790         const char* literalPlace = linePtr;
    791         if (linePtr != end && *linePtr != ',')
    792         {
    793             // try parse floating point (returns as little-endian value)
    794             try
    795             { out = asmcstrtofCStyleLEV<UIntType>(linePtr, end, linePtr); }
    796             catch(const ParseException& ex)
    797             { asmr.printError(literalPlace, ex.what()); }
    798         }
    799         else // warning
    800             asmr.printWarning(literalPlace,
    801                       "No floating point literal, zero has been put");
    802         asmr.putData(sizeof(UIntType), reinterpret_cast<const cxbyte*>(&out));
    803        
    804     } while (skipCommaForMultipleArgs(asmr, linePtr));
    805     checkGarbagesAtEnd(asmr, linePtr);
    806 }
    807 
    808 void AsmPseudoOps::putUInt128s(Assembler& asmr, const char* pseudoOpPlace,
    809                    const char* linePtr)
    810 {
    811     const char* end = asmr.line + asmr.lineSize;
    812     asmr.initializeOutputFormat();
    813     if (!asmr.isWriteableSection())
    814         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    815     skipSpacesToEnd(linePtr, end);
    816     if (linePtr == end)
    817         return;
    818     do {
    819         UInt128 value = { 0, 0 };
    820         if (linePtr != end && *linePtr != ',')
    821         {
    822             const char* literalPlace = linePtr;
    823             bool negative = false;
    824             // handle '+' and '-' before number
    825             if (*linePtr == '+')
    826                 linePtr++;
    827             else if (*linePtr == '-')
    828             {
    829                 negative = true;
    830                 linePtr++;
    831             }
    832             try
    833             { value = cstrtou128CStyle(linePtr, end, linePtr); }
    834             catch(const ParseException& ex)
    835             { asmr.printError(literalPlace, ex.what()); }
    836             if (negative)
    837             {
    838                 // negate value
    839                 value.hi = ~value.hi + (value.lo==0);
    840                 value.lo = -value.lo;
    841             }
    842         }
    843         else // warning
    844             asmr.printWarning(linePtr, "No 128-bit literal, zero has been put");
    845         UInt128 out;
    846         // and store value in little-endian
    847         SLEV(out.lo, value.lo);
    848         SLEV(out.hi, value.hi);
    849         asmr.putData(16, reinterpret_cast<const cxbyte*>(&out));
    850     } while (skipCommaForMultipleArgs(asmr, linePtr));
    851     checkGarbagesAtEnd(asmr, linePtr);
    852 }
    853 
    854 void AsmPseudoOps::putStrings(Assembler& asmr, const char* pseudoOpPlace,
    855                       const char* linePtr, bool addZero)
    856 {
    857     const char* end = asmr.line + asmr.lineSize;
    858     asmr.initializeOutputFormat();
    859     if (!asmr.isWriteableSection())
    860         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    861     skipSpacesToEnd(linePtr, end);
    862     if (linePtr == end)
    863         return;
    864     do {
    865         std::string outStr;
    866         if (*linePtr != ',')
    867         {
    868             if (asmr.parseString(outStr, linePtr))
    869                 asmr.putData(outStr.size()+(addZero), (const cxbyte*)outStr.c_str());
    870         }
    871     } while (skipCommaForMultipleArgs(asmr, linePtr));
    872     checkGarbagesAtEnd(asmr, linePtr);
    873 }
    874 
    875 // for .string16, .string32 and .string64 pseudo-ops
    876 // store characters as 16-,32-,64-bit values
    877 template<typename T>
    878 void AsmPseudoOps::putStringsToInts(Assembler& asmr, const char* pseudoOpPlace,
    879                     const char* linePtr)
    880 {
    881     const char* end = asmr.line + asmr.lineSize;
    882     if (!asmr.isWriteableSection())
    883         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    884     asmr.initializeOutputFormat();
    885     skipSpacesToEnd(linePtr, end);
    886     if (linePtr == end)
    887         return;
    888     do {
    889         std::string outStr;
    890         if (*linePtr != ',')
    891         {
    892             if (asmr.parseString(outStr, linePtr))
    893             {
    894                 const size_t strSize = outStr.size()+1;
    895                 T* outData = reinterpret_cast<T*>(
    896                         asmr.reserveData(sizeof(T)*(strSize)));
    897                 /// put as integer including nul-terminated string
    898                 for (size_t i = 0; i < strSize; i++)
    899                     SULEV(outData[i], T(outStr[i])&T(0xff));
    900             }
    901         }
    902        
    903     } while (skipCommaForMultipleArgs(asmr, linePtr));
    904     checkGarbagesAtEnd(asmr, linePtr);
    905 }
    906 
    907 void AsmPseudoOps::setSymbol(Assembler& asmr, const char* linePtr, bool reassign,
    908                  bool baseExpr)
    909 {
    910     const char* end = asmr.line + asmr.lineSize;
    911     skipSpacesToEnd(linePtr, end);
    912     const char* strAtSymName = linePtr;
    913     CString symName = extractScopedSymName(linePtr, end, false);
    914     bool good = true;
    915     if (symName.empty())
    916         ASM_NOTGOOD_BY_ERROR(linePtr, "Expected symbol")
    917     if (!skipRequiredComma(asmr, linePtr))
    918         return;
    919     if (good) // is good
    920         asmr.assignSymbol(symName, strAtSymName, linePtr, reassign, baseExpr);
    921 }
    922 
    923 void AsmPseudoOps::setSymbolBind(Assembler& asmr, const char* linePtr, cxbyte bind)
    924 {
    925     const char* end = asmr.line + asmr.lineSize;
    926     skipSpacesToEnd(linePtr, end);
    927     do {
    928         const char* symNamePlace = linePtr;
    929         AsmSymbolEntry* symEntry;
    930         Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
    931         bool good = (state != Assembler::ParseState::FAILED);
    932         // handle errors
    933         if (symEntry == nullptr)
    934             ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
    935         else if (symEntry->second.regRange)
    936             ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol must not be register symbol")
    937         else if (symEntry->second.base)
    938             ASM_NOTGOOD_BY_ERROR(symNamePlace,
    939                 "Symbol must not be set by .eqv pseudo-op or must be constant")
    940        
    941         if (good)
    942         {
    943             // set binding to symbol (except symbol '.')
    944             if (symEntry->first != ".")
    945                 symEntry->second.info = ELF32_ST_INFO(bind,
    946                       ELF32_ST_TYPE(symEntry->second.info));
    947             else
    948                 asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
    949         }
    950        
    951     } while(skipCommaForMultipleArgs(asmr, linePtr));
    952     checkGarbagesAtEnd(asmr, linePtr);
    953 }
    954 
    955 void AsmPseudoOps::setSymbolSize(Assembler& asmr, const char* linePtr)
    956 {
    957     const char* end = asmr.line + asmr.lineSize;
    958     skipSpacesToEnd(linePtr, end);
    959     const char* symNamePlace = linePtr;
    960     AsmSymbolEntry* symEntry;
    961     Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
    962     bool good = (state != Assembler::ParseState::FAILED);
    963     if (symEntry == nullptr)
    964         ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
    965     if (!skipRequiredComma(asmr, linePtr))
    966         return;
    967     // parse size
    968     uint64_t size;
    969     good &= getAbsoluteValueArg(asmr, size, linePtr, true);
    970     bool ignore = false;
    971     if (symEntry != nullptr)
    972     {
    973         if (symEntry->second.base)
    974             ASM_NOTGOOD_BY_ERROR(symNamePlace,
    975                     "Symbol must not be set by .eqv pseudo-op or must be constant")
    976         else if (symEntry->second.regRange)
    977             ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol must not be register symbol")
    978         else if (symEntry->first == ".")
    979         {
    980             // do not set size for '.' symbol
    981             asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
    982             ignore = true;
    983         }
    984     }
    985    
    986     if (good && checkGarbagesAtEnd(asmr, linePtr))
    987         if (!ignore) // ignore if '.'
    988             symEntry->second.size = size;
    989 }
    990 
    991 void AsmPseudoOps::ignoreExtern(Assembler& asmr, const char* linePtr)
    992 {
    993     const char* end = asmr.line + asmr.lineSize;
    994     skipSpacesToEnd(linePtr, end);
    995     if (linePtr == end)
    996         return;
    997     do {
    998         asmr.skipSymbol(linePtr);
    999     } while (skipCommaForMultipleArgs(asmr, linePtr));
    1000     checkGarbagesAtEnd(asmr, linePtr);
    1001 }
    1002 
    1003 void AsmPseudoOps::doFill(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1004           bool _64bit)
    1005 {
    1006     asmr.initializeOutputFormat();
    1007     const char* end = asmr.line + asmr.lineSize;
    1008    
    1009     if (!asmr.isWriteableSection())
    1010         PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
    1011    
    1012     skipSpacesToEnd(linePtr, end);
    1013     uint64_t repeat = 0, size = 1, value = 0;
    1014    
    1015     const char* reptStr = linePtr;
    1016     // parse repeat argument
    1017     bool good = getAbsoluteValueArg(asmr, repeat, linePtr, true);
    1018    
    1019     if (int64_t(repeat) < 0)
    1020         asmr.printWarning(reptStr, "Negative repeat has no effect");
    1021    
    1022     bool haveComma = false;
    1023     if (!skipComma(asmr, haveComma, linePtr))
    1024         return;
    1025     const char* sizePlace = linePtr;
    1026     const char* fillValuePlace = linePtr;
    1027     if (haveComma)
    1028     {
    1029         skipSpacesToEnd(linePtr, end);
    1030         sizePlace = linePtr; //
    1031         // parse size argument
    1032         if (getAbsoluteValueArg(asmr, size, linePtr))
    1033         {
    1034             if (int64_t(size) < 0)
    1035                 asmr.printWarning(sizePlace, "Negative size has no effect");
    1036         }
    1037         else
    1038             good = false;
    1039        
    1040         if (!skipComma(asmr, haveComma, linePtr))
    1041             return;
    1042         if (haveComma)
    1043         {
    1044             skipSpacesToEnd(linePtr, end);
    1045             fillValuePlace = linePtr;
    1046             // parse value argument
    1047             good &= getAbsoluteValueArg(asmr, value, linePtr);
    1048         }
    1049     }
    1050     if (int64_t(size) > 0 && int64_t(repeat) > 0 && SSIZE_MAX/size < repeat)
    1051         ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Product of repeat and size is too big")
    1052    
    1053     cxuint truncBits = std::min(uint64_t(8), size)<<3;
    1054     /* honors old behaviour from original GNU as (just cut to 32-bit values)
    1055      * do not that for .fillq (_64bit=true) */
    1056     if (!_64bit)
    1057         truncBits = std::min(cxuint(32), truncBits);
    1058     if (truncBits != 0 && truncBits < 64) // if print
    1059         asmr.printWarningForRange(truncBits, value, asmr.getSourcePos(fillValuePlace));
    1060    
    1061     if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // if parsing failed
    1062         return;
    1063    
    1064     if (int64_t(repeat) <= 0 || int64_t(size) <= 0)
    1065         return;
    1066    
    1067     if (!_64bit)
    1068         value &= 0xffffffffUL;
    1069    
    1070     /* do fill */
    1071     cxbyte* content = asmr.reserveData(size*repeat);
    1072     const size_t valueSize = std::min(uint64_t(8), size);
    1073     uint64_t outValue;
    1074     SLEV(outValue, value);
    1075     // main filling route (slow)
    1076     for (uint64_t r = 0; r < repeat; r++)
    1077     {
    1078         ::memcpy(content, &outValue, valueSize);
    1079         ::memset(content+valueSize, 0, size-valueSize);
    1080         content += size;
    1081     }
    1082 }
    1083 
    1084 void AsmPseudoOps::doSkip(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1085 {
    1086     asmr.initializeOutputFormat();
    1087     const char* end = asmr.line + asmr.lineSize;
    1088    
    1089     if (!asmr.isAddressableSection())
    1090         PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable "
    1091                     "section is illegal")
    1092    
    1093     skipSpacesToEnd(linePtr, end);
    1094     uint64_t size = 1, value = 0;
    1095    
    1096     const char* sizePlace = linePtr;
    1097     // parse size argument
    1098     bool good = getAbsoluteValueArg(asmr, size, linePtr);
    1099     if (int64_t(size) < 0)
    1100         asmr.printWarning(sizePlace, "Negative size has no effect");
    1101    
    1102     bool haveComma = false;
    1103     if (!skipComma(asmr, haveComma, linePtr))
    1104         return;
    1105     const char* fillValuePlace = linePtr;
    1106     if (haveComma)
    1107     {
    1108         skipSpacesToEnd(linePtr, end);
    1109         fillValuePlace = linePtr;
    1110         // parse value argument (optional)
    1111         if (getAbsoluteValueArg(asmr, value, linePtr))
    1112             asmr.printWarningForRange(8, value, asmr.getSourcePos(fillValuePlace));
    1113         else
    1114             good = false;
    1115     }
    1116     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1117         return;
    1118    
    1119     if (int64_t(size) < 0)
    1120         return;
    1121    
    1122     if (asmr.currentSection==ASMSECT_ABS && value != 0)
    1123         asmr.printWarning(fillValuePlace, "Fill value is ignored inside absolute section");
    1124     asmr.reserveData(size, value&0xff);
    1125 }
    1126 
    1127 void AsmPseudoOps::doAlign(Assembler& asmr, const char* pseudoOpPlace,
    1128                            const char* linePtr, bool powerOf2)
    1129 {
    1130     asmr.initializeOutputFormat();
    1131     const char* end = asmr.line + asmr.lineSize;
    1132    
    1133     if (!asmr.isAddressableSection())
    1134         PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable"
    1135                     " section is illegal")
    1136    
    1137     skipSpacesToEnd(linePtr, end);
    1138     uint64_t alignment, value = 0, maxAlign = 0;
    1139     const char* alignPlace = linePtr;
    1140     bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
    1141    
    1142     if (good)
    1143     {
    1144         // checking alignment value
    1145         if (powerOf2)
    1146         {
    1147             // if alignment is power of 2, then must be lesser than 64
    1148             if (alignment > 63)
    1149                 ASM_NOTGOOD_BY_ERROR(alignPlace, "Power of 2 of alignment is "
    1150                             "greater than 63")
    1151             else
    1152                 alignment = (1ULL<<alignment);
    1153         }
    1154         // checking whether alignment is power of 2
    1155         else if (alignment == 0 || (1ULL<<(63-CLZ64(alignment))) != alignment)
    1156             ASM_NOTGOOD_BY_ERROR(alignPlace, "Alignment is not power of 2")
    1157     }
    1158    
    1159     bool haveValue = false;
    1160     if (!skipComma(asmr, haveValue, linePtr))
    1161         return;
    1162     const char* valuePlace = linePtr;
    1163     if (haveValue)
    1164     {
    1165         skipSpacesToEnd(linePtr, end);
    1166         valuePlace = linePtr;
    1167         // parse value argument
    1168         if (getAbsoluteValueArg(asmr, value, linePtr))
    1169             asmr.printWarningForRange(8, value, asmr.getSourcePos(valuePlace));
    1170         else
    1171             good = false;
    1172        
    1173         bool haveComma = false;
    1174         if (!skipComma(asmr, haveComma, linePtr))
    1175             return;
    1176         if (haveComma)
    1177         {
    1178             skipSpacesToEnd(linePtr, end);
    1179             // maxalign argument
    1180             good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
    1181         }
    1182     }
    1183     if (!good || !checkGarbagesAtEnd(asmr, linePtr)) //if parsing failed
    1184         return;
    1185    
    1186     uint64_t outPos = asmr.currentOutPos;
    1187     // calculate bytes to fill (to next alignment bytes)
    1188     const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
    1189             alignment - (outPos&(alignment-1)) : 0;
    1190     if (maxAlign!=0 && bytesToFill > maxAlign)
    1191         return; // do not make alignment
    1192    
    1193     if (asmr.currentSection==ASMSECT_ABS && value != 0)
    1194         asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
    1195    
    1196     if (haveValue || asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
    1197         asmr.reserveData(bytesToFill, value&0xff);
    1198     else /* only if no value and is code section */
    1199     {
    1200         // call routine to filling alignment from ISA assembler (to fill code by nops)
    1201         cxbyte* output = asmr.reserveData(bytesToFill, 0);
    1202         asmr.isaAssembler->fillAlignment(bytesToFill, output);
    1203     }
    1204 }
    1205 
    1206 template<typename Word>
    1207 void AsmPseudoOps::doAlignWord(Assembler& asmr, const char* pseudoOpPlace,
    1208                        const char* linePtr)
    1209 {
    1210     asmr.initializeOutputFormat();
    1211     const char* end = asmr.line + asmr.lineSize;
    1212    
    1213     if (!asmr.isAddressableSection())
    1214         PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable "
    1215                     "section is illegal")
    1216    
    1217     skipSpacesToEnd(linePtr, end);
    1218     uint64_t alignment, value = 0, maxAlign = 0;
    1219     const char* alignPlace = linePtr;
    1220     bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
    1221     if (good && alignment != 0 && (1ULL<<(63-CLZ64(alignment))) != alignment)
    1222         ASM_NOTGOOD_BY_ERROR(alignPlace, "Alignment is not power of 2")
    1223    
    1224     bool haveValue = false;
    1225     if (!skipComma(asmr, haveValue, linePtr))
    1226         return;
    1227     const char* valuePlace = linePtr;
    1228     if (haveValue)
    1229     {
    1230         skipSpacesToEnd(linePtr, end);
    1231         valuePlace = linePtr;
    1232         if (getAbsoluteValueArg(asmr, value, linePtr))
    1233             asmr.printWarningForRange(sizeof(Word)<<3, value,
    1234                           asmr.getSourcePos(valuePlace));
    1235         else
    1236             good = false;
    1237        
    1238         bool haveComma = false;
    1239         if (!skipComma(asmr, haveComma, linePtr))
    1240             return;
    1241         if (haveComma)
    1242         {
    1243             skipSpacesToEnd(linePtr, end);
    1244             // maxalign argument
    1245             good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
    1246         }
    1247     }
    1248     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1249         return;
    1250    
    1251     if (alignment == 0)
    1252         return; // do nothing
    1253    
    1254     uint64_t outPos = asmr.currentOutPos;
    1255     if (outPos&(sizeof(Word)-1))
    1256         PSEUDOOP_RETURN_BY_ERROR("Offset is not aligned to word")
    1257    
    1258     // calculate bytes to fill (to next alignment bytes)
    1259     const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
    1260             alignment - (outPos&(alignment-1)) : 0;
    1261    
    1262     if (maxAlign!=0 && bytesToFill > maxAlign)
    1263         return; // do not make alignment
    1264    
    1265     if (asmr.currentSection==ASMSECT_ABS && value != 0)
    1266     {
    1267         asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
    1268         asmr.reserveData(bytesToFill);
    1269         return;
    1270     }
    1271     cxbyte* content = asmr.reserveData(bytesToFill);
    1272     if (haveValue)
    1273     {
    1274         Word word;
    1275         SLEV(word, value);
    1276         std::fill(reinterpret_cast<Word*>(content),
    1277                   reinterpret_cast<Word*>(content + bytesToFill), word);
    1278     }
    1279     else if (asmr.sections[asmr.currentSection].type == AsmSectionType::CODE)
    1280         // call routine to filling alignment from ISA assembler (to fill code by nops)
    1281         asmr.isaAssembler->fillAlignment(bytesToFill, content);
    1282 }
    1283 
    1284 void AsmPseudoOps::doOrganize(Assembler& asmr, const char* linePtr)
    1285 {
    1286     asmr.initializeOutputFormat();
    1287     const char* end = asmr.line + asmr.lineSize;
    1288     skipSpacesToEnd(linePtr, end);
    1289     uint64_t value;
    1290     cxuint sectionId = ASMSECT_ABS;
    1291     const char* valuePlace = linePtr;
    1292     bool good = getAnyValueArg(asmr, value, sectionId, linePtr);
    1293    
    1294     uint64_t fillValue = 0;
    1295     bool haveComma;
    1296     if (!skipComma(asmr, haveComma, linePtr))
    1297         return;
    1298     const char* fillValuePlace = linePtr;
    1299     if (haveComma)
    1300     {
    1301         // optional fill argument
    1302         skipSpacesToEnd(linePtr, end);
    1303         fillValuePlace = linePtr;
    1304         good = getAbsoluteValueArg(asmr, fillValue, linePtr, true);
    1305     }
    1306     asmr.printWarningForRange(8, fillValue, asmr.getSourcePos(fillValuePlace));
    1307    
    1308     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1309         return;
    1310    
    1311     asmr.assignOutputCounter(valuePlace, value, sectionId, fillValue);
    1312 }
    1313 
    1314 void AsmPseudoOps::doPrint(Assembler& asmr, const char* linePtr)
    1315 {
    1316     std::string outStr;
    1317     if (!asmr.parseString(outStr, linePtr))
    1318         return;
    1319     if (!AsmPseudoOps::checkGarbagesAtEnd(asmr, linePtr))
    1320         return;
    1321     asmr.printStream.write(outStr.c_str(), outStr.size());
    1322     asmr.printStream.put('\n');
    1323 }
    1324 
    1325 /// perform .if for integer comparisons '.iflt', '.ifle', '.ifne'
    1326 void AsmPseudoOps::doIfInt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1327                IfIntComp compType, bool elseIfClause)
    1328 {
    1329     const char* end = asmr.line + asmr.lineSize;
    1330     skipSpacesToEnd(linePtr, end);
    1331     uint64_t value;
    1332     bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
    1333     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1334         return;
    1335    
    1336     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1337             AsmClauseType::IF;
    1338     bool satisfied;
    1339     switch(compType)
    1340     {
    1341         case IfIntComp::EQUAL:
    1342             satisfied = (value == 0);
    1343             break;
    1344         case IfIntComp::NOT_EQUAL:
    1345             satisfied = (value != 0);
    1346             break;
    1347         case IfIntComp::LESS:
    1348             satisfied = (int64_t(value) < 0);
    1349             break;
    1350         case IfIntComp::LESS_EQUAL:
    1351             satisfied = (int64_t(value) <= 0);
    1352             break;
    1353         case IfIntComp::GREATER:
    1354             satisfied = (int64_t(value) > 0);
    1355             break;
    1356         case IfIntComp::GREATER_EQUAL:
    1357             satisfied = (int64_t(value) >= 0);
    1358             break;
    1359         default:
    1360             satisfied = false;
    1361             break;
    1362     }
    1363     bool included;
    1364     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1365     {   //
    1366         if (!included) // skip clauses (do not perform statements)
    1367             asmr.skipClauses();
    1368     }
    1369 }
    1370 
    1371 // .ifdef (or .ifndef if negation is true)
    1372 void AsmPseudoOps::doIfDef(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1373                bool negation, bool elseIfClause)
    1374 {
    1375     const char* end = asmr.line + asmr.lineSize;
    1376     skipSpacesToEnd(linePtr, end);
    1377     const char* symNamePlace = linePtr;
    1378     AsmSymbolEntry* entry;
    1379     bool good = true;
    1380     // parse symbol
    1381     Assembler::ParseState state = asmr.parseSymbol(linePtr, entry, false, true);
    1382     if (state == Assembler::ParseState::FAILED)
    1383         return;
    1384     if (state == Assembler::ParseState::MISSING)
    1385         ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol")
    1386     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1387         return;
    1388    
    1389     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1390             AsmClauseType::IF;
    1391     bool included;
    1392     const bool symDefined = (entry!=nullptr && entry->second.isDefined());
    1393     bool satisfied = (!negation) ?  symDefined : !symDefined;
    1394     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1395     {   //
    1396         if (!included) // skip clauses (do not perform statements)
    1397             asmr.skipClauses();
    1398     }
    1399 }
    1400 
    1401 // .ifb (or .ifnb if negation is true)
    1402 void AsmPseudoOps::doIfBlank(Assembler& asmr, const char* pseudoOpPlace,
    1403              const char* linePtr, bool negation, bool elseIfClause)
    1404 {
    1405     const char* end = asmr.line + asmr.lineSize;
    1406     skipSpacesToEnd(linePtr, end);
    1407    
    1408     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1409             AsmClauseType::IF;
    1410     bool included;
    1411     bool satisfied = (!negation) ? linePtr==end : linePtr!=end;
    1412     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1413     {   //
    1414         if (!included) // skip clauses (do not perform statements)
    1415             asmr.skipClauses();
    1416     }
    1417 }
    1418 
    1419 // this routine get string to compare in rules given GNU as
    1420 static std::string getStringToCompare(const char* strStart, const char* strEnd)
    1421 {
    1422     std::string firstStr;
    1423     bool blank = true;
    1424     bool singleQuote = false;
    1425     bool dblQuote = false;
    1426     cxbyte prevTok = 0;
    1427     for (const char* s = strStart; s != strEnd; ++s)
    1428         if (isSpace(*s))
    1429         {
    1430             if (!blank || dblQuote || singleQuote)
    1431                 firstStr.push_back(*s);
    1432             blank = true;
    1433         }
    1434         else
    1435         {
    1436             blank = false;
    1437             if (*s == '"' && !singleQuote)
    1438                 dblQuote = !dblQuote;
    1439             else if (*s == '\'' && !dblQuote)
    1440                 singleQuote = !singleQuote;
    1441            
    1442             /* original GNU as tokenize line before processing, this code 'emulates'
    1443              * this operation */
    1444             cxbyte thisTok = (cxbyte(*s) >= 0x20 && cxbyte(*s) <= 0x80) ?
    1445                     tokenCharTable[*s-0x20] : 0;
    1446             if (!singleQuote && !dblQuote && !firstStr.empty() &&
    1447                 isSpace(firstStr.back()) &&
    1448                 ((prevTok != thisTok) || ((prevTok == thisTok) && (prevTok & 0x80)==0)))
    1449                 firstStr.pop_back();// delete space between different tokens
    1450            
    1451             firstStr.push_back(*s);
    1452             prevTok = thisTok;
    1453         }
    1454     if (!firstStr.empty() && isSpace(firstStr.back()))
    1455         firstStr.pop_back(); // remove last space
    1456     return firstStr;
    1457 }
    1458 
    1459 void AsmPseudoOps::doIfCmpStr(Assembler& asmr, const char* pseudoOpPlace,
    1460                const char* linePtr, bool negation, bool elseIfClause)
    1461 {
    1462     const char* end = asmr.line + asmr.lineSize;
    1463     skipSpacesToEnd(linePtr, end);
    1464     const char* firstStrStart = linePtr;
    1465     bool good = true;
    1466     while (linePtr != end && *linePtr != ',') linePtr++;
    1467     if (linePtr == end)
    1468         ASM_RETURN_BY_ERROR(linePtr, "Missing second string")
    1469     const char* firstStrEnd = linePtr;
    1470     if (good) linePtr++; // comma
    1471     else return;
    1472    
    1473     std::string firstStr = getStringToCompare(firstStrStart, firstStrEnd);
    1474     std::string secondStr = getStringToCompare(linePtr, end);
    1475    
    1476     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1477             AsmClauseType::IF;
    1478     bool included;
    1479     bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
    1480     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1481     {   //
    1482         if (!included) // skip clauses (do not perform statements)
    1483             asmr.skipClauses();
    1484     }
    1485 }
    1486 
    1487 void AsmPseudoOps::doIfStrEqual(Assembler& asmr, const char* pseudoOpPlace,
    1488                 const char* linePtr, bool negation, bool elseIfClause)
    1489 {
    1490     const char* end = asmr.line + asmr.lineSize;
    1491     skipSpacesToEnd(linePtr, end);
    1492     std::string firstStr, secondStr;
    1493     bool good = asmr.parseString(firstStr, linePtr);
    1494     if (!skipRequiredComma(asmr, linePtr))
    1495         return;
    1496     skipSpacesToEnd(linePtr, end);
    1497     good &= asmr.parseString(secondStr, linePtr);
    1498     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1499         return;
    1500    
    1501     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1502             AsmClauseType::IF;
    1503     bool included;
    1504     bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
    1505     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1506     {   //
    1507         if (!included) // skip clauses (do not perform statements)
    1508             asmr.skipClauses();
    1509     }
    1510 }
    1511 
    1512 void AsmPseudoOps::doIf64Bit(Assembler& asmr, const char* pseudoOpPlace,
    1513                 const char* linePtr, bool negation, bool elseIfClause)
    1514 {
    1515     if (!checkGarbagesAtEnd(asmr, linePtr))
    1516         return;
    1517    
    1518     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1519             AsmClauseType::IF;
    1520     bool included;
    1521     bool satisfied = (!negation) ? asmr._64bit : !asmr._64bit;
    1522     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1523     {   //
    1524         if (!included) // skip clauses (do not perform statements)
    1525             asmr.skipClauses();
    1526     }
    1527 }
    1528 
    1529 void AsmPseudoOps::doIfArch(Assembler& asmr, const char* pseudoOpPlace,
    1530             const char* linePtr, bool negation, bool elseIfClause)
    1531 {
    1532     const char* end = asmr.line + asmr.lineSize;
    1533     skipSpacesToEnd(linePtr, end);
    1534     char deviceName[64];
    1535     const char* archNamePlace = linePtr;
    1536     if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
    1537         return;
    1538     GPUArchitecture arch;
    1539     try
    1540     {
    1541         arch = getGPUArchitectureFromName(deviceName);
    1542         if (!checkGarbagesAtEnd(asmr, linePtr))
    1543             return;
    1544     }
    1545     catch(const Exception& ex)
    1546     {
    1547         // if architecture not found (unknown architecture)
    1548         asmr.printError(archNamePlace, ex.what());
    1549         return;
    1550     }
    1551    
    1552     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1553             AsmClauseType::IF;
    1554     bool included;
    1555     GPUArchitecture curArch = getGPUArchitectureFromDeviceType(asmr.getDeviceType());
    1556     bool satisfied = (!negation) ? arch==curArch : arch!=curArch;
    1557     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1558     {   //
    1559         if (!included) // skip clauses (do not perform statements)
    1560             asmr.skipClauses();
    1561     }
    1562 }
    1563 
    1564 void AsmPseudoOps::doIfGpu(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1565             bool negation, bool elseIfClause)
    1566 {
    1567     const char* end = asmr.line + asmr.lineSize;
    1568     skipSpacesToEnd(linePtr, end);
    1569     char deviceName[64];
    1570     const char* deviceNamePlace = linePtr;
    1571     if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
    1572         return;
    1573     GPUDeviceType deviceType;
    1574     try
    1575     {
    1576         deviceType = getGPUDeviceTypeFromName(deviceName);
    1577         if (!checkGarbagesAtEnd(asmr, linePtr))
    1578             return;
    1579     }
    1580     catch(const Exception& ex)
    1581     {
    1582         // if GPU device name is unknown, print error
    1583         asmr.printError(deviceNamePlace, ex.what());
    1584         return;
    1585     }
    1586    
    1587     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1588             AsmClauseType::IF;
    1589     bool included;
    1590     bool satisfied = (!negation) ? deviceType==asmr.deviceType :
    1591                 deviceType!=asmr.deviceType;
    1592     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1593     {   //
    1594         if (!included) // skip clauses (do not perform statements)
    1595             asmr.skipClauses();
    1596     }
    1597 }
    1598 
    1599 void AsmPseudoOps::doIfFmt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1600             bool negation, bool elseIfClause)
    1601 {
    1602     const char* end = asmr.line + asmr.lineSize;
    1603     skipSpacesToEnd(linePtr, end);
    1604     BinaryFormat format;
    1605     // parse binary format name
    1606     if (!parseFormat(asmr, linePtr, format))
    1607         return;
    1608    
    1609     const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
    1610             AsmClauseType::IF;
    1611     bool included;
    1612     bool satisfied = (!negation) ? format==asmr.format: format!=asmr.format;
    1613     if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
    1614     {   //
    1615         if (!included) // skip clauses (do not perform statements)
    1616             asmr.skipClauses();
    1617     }
    1618 }
    1619 
    1620 void AsmPseudoOps::doElse(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1621 {
    1622     if (!checkGarbagesAtEnd(asmr, linePtr))
    1623         return;
    1624     bool included;
    1625     if (asmr.pushClause(pseudoOpPlace, AsmClauseType::ELSE, true, included))
    1626     {
    1627         if (!included) // skip clauses (do not perform statements)
    1628             asmr.skipClauses();
    1629     }
    1630 }
    1631 
    1632 void AsmPseudoOps::endIf(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1633 {
    1634     if (!checkGarbagesAtEnd(asmr, linePtr))
    1635         return;
    1636     asmr.popClause(pseudoOpPlace, AsmClauseType::IF);
    1637 }
    1638 
    1639 void AsmPseudoOps::doRepeat(Assembler& asmr, const char* pseudoOpPlace,
    1640                     const char* linePtr)
    1641 {
    1642     const char* end = asmr.line + asmr.lineSize;
    1643     skipSpacesToEnd(linePtr, end);
    1644     uint64_t repeatsNum;
    1645     bool good = getAbsoluteValueArg(asmr, repeatsNum, linePtr, true);
    1646     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1647         return;
    1648    
    1649     if (asmr.repetitionLevel == 1000)
    1650         PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
    1651     asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
    1652     if (repeatsNum == 0)
    1653     {
    1654         /* skip it */
    1655         asmr.skipClauses();
    1656         return;
    1657     }
    1658     /* create repetition (even if only 1 - for correct source position included
    1659      * to messages from repetition) */
    1660     std::unique_ptr<AsmRepeat> repeat(new AsmRepeat(
    1661                 asmr.getSourcePos(pseudoOpPlace), repeatsNum));
    1662     if (asmr.putRepetitionContent(*repeat))
    1663     {
    1664         // and input stream filter
    1665         std::unique_ptr<AsmInputFilter> newInputFilter(
    1666                     new AsmRepeatInputFilter(repeat.release()));
    1667         asmr.asmInputFilters.push(newInputFilter.release());
    1668         asmr.currentInputFilter = asmr.asmInputFilters.top();
    1669         asmr.repetitionLevel++;
    1670     }
    1671 }
    1672 
    1673 void AsmPseudoOps::endRepeat(Assembler& asmr, const char* pseudoOpPlace,
    1674                    const char* linePtr)
    1675 {
    1676     if (!checkGarbagesAtEnd(asmr, linePtr))
    1677         return;
    1678     asmr.popClause(pseudoOpPlace, AsmClauseType::REPEAT);
    1679 }
    1680 
    1681 void AsmPseudoOps::doMacro(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1682 {
    1683     const char* end = asmr.line + asmr.lineSize;
    1684     skipSpacesToEnd(linePtr, end);
    1685     const char* macroNamePlace = linePtr;
    1686     CString macroName = extractSymName(linePtr, end, false);
    1687     if (macroName.empty())
    1688         ASM_RETURN_BY_ERROR(macroNamePlace, "Expected macro name")
    1689     // convert to lower (name is case-insensitive)
    1690     if (asmr.macroCase)
    1691         toLowerString(macroName);
    1692     /* parse args */
    1693     std::vector<AsmMacroArg> args;
    1694    
    1695     bool good = true;
    1696     bool haveVarArg = false;
    1697    
    1698     if (asmr.macroMap.find(macroName) != asmr.macroMap.end())
    1699         ASM_NOTGOOD_BY_ERROR(macroNamePlace, (std::string("Macro '") + macroName.c_str() +
    1700                 "' is already defined").c_str())
    1701    
    1702     {
    1703     std::unordered_set<CString> macroArgSet;
    1704     while(linePtr != end)
    1705     {
    1706         skipSpacesToEnd(linePtr, end);
    1707         if (linePtr != end && *linePtr == ',')
    1708             skipCharAndSpacesToEnd(linePtr, end);
    1709         const char* argPlace = linePtr;
    1710         CString argName = extractSymName(linePtr, end, false);
    1711         if (argName.empty())
    1712             ASM_RETURN_BY_ERROR(argPlace, "Expected macro argument name")
    1713         bool argRequired = false;
    1714         bool argVarArgs = false;
    1715         bool argGood = true;
    1716         std::string defaultArgValue;
    1717        
    1718         if (!macroArgSet.insert(argName).second)
    1719             // duplicate!
    1720             ASM_NOTGOOD_BY_ERROR1(argGood, argPlace, (std::string(
    1721                     "Duplicated macro argument '")+ argName.c_str()+'\'').c_str())
    1722        
    1723         skipSpacesToEnd(linePtr, end);
    1724         if (linePtr != end && *linePtr == ':')
    1725         {
    1726             // parse argument's qualifier
    1727             skipCharAndSpacesToEnd(linePtr, end);
    1728             //extr
    1729             if (linePtr+3 <= end && linePtr[0] == 'r' && linePtr[1] == 'e' &&
    1730                     linePtr[2] == 'q') // reqd (if argument required)
    1731             {
    1732                 argRequired = true;
    1733                 linePtr += 3;
    1734             }
    1735             else if (linePtr+6 <= end && ::memcmp(linePtr, "vararg", 6)==0) // required
    1736             {
    1737                 argVarArgs = true;
    1738                 linePtr += 6;
    1739             }
    1740             else // otherwise
    1741                 ASM_NOTGOOD_BY_ERROR1(argGood, linePtr,
    1742                         "Expected qualifier 'req' or 'vararg'")
    1743         }
    1744         skipSpacesToEnd(linePtr, end);
    1745         if (linePtr != end && *linePtr == '=')
    1746         {
    1747             // parse default value
    1748             skipCharAndSpacesToEnd(linePtr, end);
    1749             const char* defaultValueStr = linePtr;
    1750             if (!asmr.parseMacroArgValue(linePtr, defaultArgValue))
    1751             {
    1752                 good = false;
    1753                 continue; // error
    1754             }
    1755             if (argRequired)
    1756                 asmr.printWarning(defaultValueStr, (std::string(
    1757                         "Pointless default value for argument '") +
    1758                         argName.c_str()+'\'').c_str());
    1759         }
    1760        
    1761         if (argGood)
    1762         {
    1763             // push to arguments
    1764             if (haveVarArg)
    1765                 ASM_NOTGOOD_BY_ERROR(argPlace, "Variadic argument must be last")
    1766             else
    1767                 haveVarArg = argVarArgs;
    1768         }
    1769         else // not good
    1770             good = false;
    1771        
    1772         if (argGood) // push argument
    1773             args.push_back({argName, defaultArgValue, argVarArgs, argRequired});
    1774     }
    1775     }
    1776     if (good)
    1777     {   
    1778         if (checkPseudoOpName(macroName))
    1779         {
    1780             // ignore if name of macro is name of pseudo op name
    1781             asmr.printWarning(pseudoOpPlace, (std::string(
    1782                         "Attempt to redefine pseudo-op '")+macroName.c_str()+
    1783                         "' as macro. Ignoring it...").c_str());
    1784             asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
    1785             asmr.skipClauses();
    1786             return;
    1787         }
    1788         // create a macro and put macro map
    1789         RefPtr<const AsmMacro> macro(new AsmMacro(asmr.getSourcePos(pseudoOpPlace),
    1790                         Array<AsmMacroArg>(args.begin(), args.end())));
    1791         asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
    1792         if (!asmr.putMacroContent(macro.constCast<AsmMacro>()))
    1793             return;
    1794         asmr.macroMap.insert(std::make_pair(std::move(macroName), std::move(macro)));
    1795     }
    1796 }
    1797 
    1798 void AsmPseudoOps::endMacro(Assembler& asmr, const char* pseudoOpPlace,
    1799                     const char* linePtr)
    1800 {
    1801     if (!checkGarbagesAtEnd(asmr, linePtr))
    1802         return;
    1803     asmr.popClause(pseudoOpPlace, AsmClauseType::MACRO);
    1804 }
    1805 
    1806 void AsmPseudoOps::exitMacro(Assembler& asmr, const char* pseudoOpPlace,
    1807                    const char* linePtr)
    1808 {
    1809     if (!checkGarbagesAtEnd(asmr, linePtr))
    1810         return;
    1811    
    1812     const AsmInputFilterType type = asmr.currentInputFilter->getType();
    1813     if (type == AsmInputFilterType::STREAM)
    1814         asmr.printWarning(pseudoOpPlace, "'.exitm' is ignored outside macro content");
    1815     else
    1816     {
    1817         if (type == AsmInputFilterType::REPEAT)
    1818             asmr.printWarning(pseudoOpPlace, "Behavior of '.exitm' inside repeat is "
    1819                     "undefined. Exiting from repeat...");
    1820         // skipping clauses to current macro
    1821         asmr.skipClauses(true);
    1822     }
    1823 }
    1824 
    1825 void AsmPseudoOps::doIRP(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
    1826               bool perChar)
    1827 {
    1828     const char* end = asmr.line + asmr.lineSize;
    1829     skipSpacesToEnd(linePtr, end);
    1830     const char* symNamePlace = linePtr;
    1831     CString symName = extractSymName(linePtr, end, false);
    1832     if (symName.empty())
    1833         ASM_RETURN_BY_ERROR(symNamePlace, "Expected argument name")
    1834     /* parse args */
    1835     std::vector<CString> symValues;
    1836     std::string symValString;
    1837    
    1838     bool good = true;
    1839     skipSpacesToEnd(linePtr, end);
    1840     if (linePtr != end && *linePtr == ',')
    1841         skipCharAndSpacesToEnd(linePtr, end);
    1842    
    1843     // parse list of symvalues for repetitions
    1844     while(linePtr != end)
    1845     {
    1846         if (linePtr != end && *linePtr == ',')
    1847         {
    1848             if (perChar)
    1849                 // because if value stores as character we add ','
    1850                 symValString.push_back(',');
    1851             skipCharAndSpacesToEnd(linePtr, end);
    1852         }
    1853         std::string symValue;
    1854         if (!asmr.parseMacroArgValue(linePtr, symValue))
    1855         {
    1856             good = false;
    1857             continue; // error
    1858         }
    1859         skipSpacesToEnd(linePtr, end);
    1860         if (!perChar)
    1861             // push single sym value
    1862             symValues.push_back(symValue);
    1863         else
    1864             // otherwise this sym value as string of values
    1865             symValString += symValue;
    1866     }
    1867    
    1868     // check depth of repetitions
    1869     if (asmr.repetitionLevel == 1000)
    1870         PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
    1871    
    1872     if (symValues.empty())
    1873         symValues.push_back("");
    1874     if (good)
    1875     {
    1876         // create IRP repetition
    1877         asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
    1878         std::unique_ptr<AsmIRP> repeat;
    1879         if (!perChar)
    1880             repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
    1881                       symName, Array<CString>(symValues.begin(), symValues.end())));
    1882         else // per char
    1883             repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
    1884                       symName, symValString));
    1885        
    1886         if (asmr.putRepetitionContent(*repeat))
    1887         {
    1888             // and input stream filter
    1889             std::unique_ptr<AsmInputFilter> newInputFilter(
    1890                         new AsmIRPInputFilter(repeat.release()));
    1891             asmr.asmInputFilters.push(newInputFilter.release());
    1892             asmr.currentInputFilter = asmr.asmInputFilters.top();
    1893             asmr.repetitionLevel++;
    1894         }
    1895     }
    1896 }
    1897 
    1898 void AsmPseudoOps::doFor(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1899 {
    1900     const char* end = asmr.line+asmr.lineSize;
    1901     skipSpacesToEnd(linePtr, end);
    1902     const char* symNamePlace = linePtr;
    1903     AsmSymbolEntry* iterSymbol = nullptr;
    1904     const CString symName = extractScopedSymName(linePtr, end, false);
    1905     if (symName.empty())
    1906         ASM_RETURN_BY_ERROR(symNamePlace, "Illegal symbol name")
    1907     size_t symNameLength = symName.size();
    1908     // special case for '.' symbol (check whether is in global scope)
    1909     if (symNameLength >= 3 && symName.compare(symNameLength-3, 3, "::.")==0)
    1910         ASM_RETURN_BY_ERROR(symNamePlace, "Symbol '.' can be only in global scope")
    1911    
    1912     bool good = true;
    1913     skipSpacesToEnd(linePtr, end);
    1914     if (linePtr==end || *linePtr!='=')
    1915         ASM_NOTGOOD_BY_ERROR(linePtr, "Expected '='")
    1916     skipCharAndSpacesToEnd(linePtr, end);
    1917     uint64_t value = 0;
    1918     cxuint sectionId = ASMSECT_ABS;
    1919     good &= AsmParseUtils::getAnyValueArg(asmr, value, sectionId, linePtr);
    1920     if (good)
    1921     {
    1922         std::pair<AsmSymbolEntry*, bool> res = asmr.insertSymbolInScope(symName,
    1923                     AsmSymbol(sectionId, value));
    1924         if (!res.second)
    1925         {
    1926             // if symbol found
    1927             if (res.first->second.onceDefined && res.first->second.isDefined()) // if label
    1928             {
    1929                 asmr.printError(symNamePlace, (std::string("Symbol '")+symName.c_str()+
    1930                             "' is already defined").c_str());
    1931                 good = false;
    1932             }
    1933             else // set value of symbol
    1934                 asmr.setSymbol(*res.first, value, sectionId);
    1935         }
    1936         else // set hasValue (by isResolvableSection
    1937             res.first->second.hasValue = asmr.isResolvableSection(sectionId);
    1938         iterSymbol = res.first;
    1939     }
    1940    
    1941     if (!skipRequiredComma(asmr, linePtr))
    1942         return;
    1943     std::unique_ptr<AsmExpression> condExpr(AsmExpression::parse(asmr, linePtr, true));
    1944     if (!skipRequiredComma(asmr, linePtr))
    1945         return;
    1946     std::unique_ptr<AsmExpression> nextExpr(AsmExpression::parse(asmr, linePtr, true));
    1947    
    1948     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1949         return;
    1950    
    1951     if (condExpr==nullptr || nextExpr==nullptr)
    1952         return; // if no expressions
    1953    
    1954     // check depth of repetitions
    1955     if (asmr.repetitionLevel == 1000)
    1956         PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
    1957    
    1958     // create AsmFor
    1959     asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
    1960     std::unique_ptr<AsmFor> repeat(new AsmFor(
    1961                 asmr.getSourcePos(pseudoOpPlace), iterSymbol, condExpr.get(),
    1962                 nextExpr.get()));
    1963     condExpr.release();
    1964     nextExpr.release();
    1965     if (asmr.putRepetitionContent(*repeat))
    1966     {
    1967         // and input stream filter
    1968         std::unique_ptr<AsmInputFilter> newInputFilter(
    1969                     new AsmForInputFilter(repeat.release()));
    1970         asmr.asmInputFilters.push(newInputFilter.release());
    1971         asmr.currentInputFilter = asmr.asmInputFilters.top();
    1972         asmr.repetitionLevel++;
    1973     }
    1974 }
    1975 
    1976 void AsmPseudoOps::doWhile(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
    1977 {
    1978     std::unique_ptr<AsmExpression> condExpr(AsmExpression::parse(asmr, linePtr, true));
    1979     if (!checkGarbagesAtEnd(asmr, linePtr))
    1980         return;
    1981    
    1982     if (condExpr==nullptr)
    1983         return; // if no expressions
    1984    
    1985     // check depth of repetitions
    1986     if (asmr.repetitionLevel == 1000)
    1987         PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
    1988    
    1989     // create AsmFor
    1990     asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
    1991     std::unique_ptr<AsmFor> repeat(new AsmFor(
    1992                 asmr.getSourcePos(pseudoOpPlace), nullptr, condExpr.get(), nullptr));
    1993     condExpr.release();
    1994     if (asmr.putRepetitionContent(*repeat))
    1995     {
    1996         // and input stream filter
    1997         std::unique_ptr<AsmInputFilter> newInputFilter(
    1998                     new AsmForInputFilter(repeat.release()));
    1999         asmr.asmInputFilters.push(newInputFilter.release());
    2000         asmr.currentInputFilter = asmr.asmInputFilters.top();
    2001         asmr.repetitionLevel++;
    2002     }
    2003 }
    2004 
    2005 void AsmPseudoOps::purgeMacro(Assembler& asmr, const char* linePtr)
    2006 {
    2007     const char* end = asmr.line+asmr.lineSize;
    2008     skipSpacesToEnd(linePtr, end);
    2009     const char* macroNamePlace = linePtr;
    2010     CString macroName = extractSymName(linePtr, end, false);
    2011     bool good = true;
    2012     if (macroName.empty())
    2013         ASM_NOTGOOD_BY_ERROR(macroNamePlace, "Expected macro name")
    2014     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2015         return;
    2016     // convert to lower (name is case-insensitive)
    2017     if (asmr.macroCase)
    2018         toLowerString(macroName); // macro name is lowered
    2019    
    2020     if (!asmr.macroMap.erase(macroName))
    2021         asmr.printWarning(macroNamePlace, (std::string("Macro '")+macroName.c_str()+
    2022                 "' already doesn't exist").c_str());
    2023 }
    2024 
    2025 void AsmPseudoOps::openScope(Assembler& asmr, const char* pseudoOpPlace,
    2026                      const char* linePtr)
    2027 {
    2028     const char* end = asmr.line+asmr.lineSize;
    2029     skipSpacesToEnd(linePtr, end);
    2030     CString scopeName = extractSymName(linePtr, end, false);
    2031     bool good = true;
    2032     // check depth of scopes
    2033     if (asmr.scopeStack.size() == 1000)
    2034         ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Scope level is greater than 1000")
    2035     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2036         return;
    2037    
    2038     asmr.pushScope(scopeName);
    2039 }
    2040 
    2041 void AsmPseudoOps::closeScope(Assembler& asmr, const char* pseudoOpPlace,
    2042                       const char* linePtr)
    2043 {
    2044     const char* end = asmr.line+asmr.lineSize;
    2045     skipSpacesToEnd(linePtr, end);
    2046     bool good = true;
    2047     if (asmr.scopeStack.empty())
    2048         ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Closing global scope is illegal")
    2049     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2050         return;
    2051     asmr.popScope();
    2052 }
    2053 
    2054 void AsmPseudoOps::startUsing(Assembler& asmr, const char* linePtr)
    2055 {
    2056     const char* end = asmr.line+asmr.lineSize;
    2057     skipSpacesToEnd(linePtr, end);
    2058     const char* scopePathPlace = linePtr;
    2059     CString scopePath = extractScopedSymName(linePtr, end);
    2060     bool good = true;
    2061     if (scopePath.empty() || scopePath == "::")
    2062         ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
    2063     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2064         return;
    2065     AsmScope* scope = asmr.getRecurScope(scopePath);
    2066     // do add this
    2067     asmr.currentScope->startUsingScope(scope);
    2068 }
    2069 
    2070 void AsmPseudoOps::doUseReg(Assembler& asmr, const char* linePtr)
    2071 {
    2072     const char* end = asmr.line+asmr.lineSize;
    2073     asmr.initializeOutputFormat();
    2074    
    2075     do {
    2076         skipSpacesToEnd(linePtr, end);
    2077         bool good = true;
    2078         cxuint regStart, regEnd;
    2079         const AsmRegVar* regVar;
    2080         good = asmr.isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar);
    2081         skipSpacesToEnd(linePtr, end);
    2082         if (linePtr==end || *linePtr!=':')
    2083         {
    2084             asmr.printError(linePtr, "Expected colon after register");
    2085             continue;
    2086         }
    2087         skipCharAndSpacesToEnd(linePtr, end);
    2088        
    2089         cxbyte rwFlags = 0;
    2090         // parse read/write flags (r,w,rw)
    2091         for (; linePtr != end; linePtr++)
    2092         {
    2093             char c = toLower(*linePtr);
    2094             if (c!='r' && c!='w')
    2095                 break;
    2096             rwFlags |= (c=='r') ? ASMRVU_READ : ASMRVU_WRITE;
    2097         }
    2098         if (rwFlags==0) // not parsed
    2099         {
    2100             asmr.printError(linePtr, "Expected access mask");
    2101             continue;
    2102         }
    2103        
    2104         if (good) // if good
    2105         {
    2106             // create usageHandler if needed
    2107             if (asmr.sections[asmr.currentSection].usageHandler == nullptr)
    2108                     asmr.sections[asmr.currentSection].usageHandler.reset(
    2109                             asmr.isaAssembler->createUsageHandler(
    2110                                     asmr.sections[asmr.currentSection].content));
    2111             // put regVar usage
    2112             asmr.sections[asmr.currentSection].usageHandler->pushUseRegUsage(
    2113                 AsmRegVarUsage{ size_t(asmr.currentOutPos), regVar,
    2114                     uint16_t(regStart), uint16_t(regEnd), ASMFIELD_NONE, rwFlags, 0 });
    2115         }
    2116        
    2117     } while(skipCommaForMultipleArgs(asmr, linePtr));
    2118    
    2119     checkGarbagesAtEnd(asmr, linePtr);
    2120 }
    2121 
    2122 void AsmPseudoOps::stopUsing(Assembler& asmr, const char* linePtr)
    2123 {
    2124     const char* end = asmr.line+asmr.lineSize;
    2125     skipSpacesToEnd(linePtr, end);
    2126     const char* scopePathPlace = linePtr;
    2127     CString scopePath = extractScopedSymName(linePtr, end);
    2128     bool good = true;
    2129     if (scopePath == "::")
    2130         ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
    2131     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2132         return;
    2133     AsmScope* scope = asmr.getRecurScope(scopePath);
    2134     if (!scopePath.empty())
    2135         asmr.currentScope->stopUsingScope(scope);
    2136     else // stop using all scopes
    2137         asmr.currentScope->stopUsingScopes();
    2138 }
    2139 
    2140 void AsmPseudoOps::undefSymbol(Assembler& asmr, const char* linePtr)
    2141 {
    2142     const char* end = asmr.line+asmr.lineSize;
    2143     skipSpacesToEnd(linePtr, end);
    2144     const char* symNamePlace = linePtr;
    2145     CString symName = extractScopedSymName(linePtr, end, false);
    2146     bool good = true;
    2147     if (symName.empty())
    2148         ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
    2149     // symbol '.' can not be undefined
    2150     else if (symName == ".")
    2151         ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol '.' can not be undefined")
    2152     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2153         return;
    2154    
    2155     CString sameSymName;
    2156     AsmScope* outScope;
    2157     AsmSymbolEntry* it = asmr.findSymbolInScope(symName, outScope, sameSymName);
    2158     if (it == nullptr || !it->second.isDefined())
    2159         asmr.printWarning(symNamePlace, (std::string("Symbol '") + symName.c_str() +
    2160                 "' already doesn't exist").c_str());
    2161     else // always undefine (do not remove, due to .eqv evaluation)
    2162         asmr.undefineSymbol(*it);
    2163 }
    2164 
    2165 void AsmPseudoOps::setAbsoluteOffset(Assembler& asmr, const char* linePtr)
    2166 {
    2167     const char* end = asmr.line+asmr.lineSize;
    2168     asmr.initializeOutputFormat();
    2169     skipSpacesToEnd(linePtr, end);
    2170     uint64_t value = 0;
    2171     bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
    2172     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2173         return;
    2174     asmr.currentSection = ASMSECT_ABS;
    2175     asmr.currentOutPos = value;
    2176 }
    2177 
    2178 void AsmPseudoOps::defRegVar(Assembler& asmr, const char* linePtr)
    2179 {
    2180     const char* end = asmr.line+asmr.lineSize;
    2181     asmr.initializeOutputFormat();
    2182    
    2183     do {
    2184         skipSpacesToEnd(linePtr, end);
    2185         const char* regNamePlace = linePtr;
    2186         CString name = extractScopedSymName(linePtr, end, false);
    2187         bool good = true;
    2188         if (name.empty())
    2189             ASM_NOTGOOD_BY_ERROR(regNamePlace, "Expected reg-var name")
    2190         skipSpacesToEnd(linePtr, end);
    2191         if (linePtr==end || *linePtr!=':')
    2192         {
    2193             asmr.printError(linePtr, "Expected colon after reg-var");
    2194             continue;
    2195         }
    2196         skipCharAndSpacesToEnd(linePtr, end);
    2197         AsmRegVar var = { 0, 1 };
    2198         if (!asmr.isaAssembler->parseRegisterType(linePtr, end, var.type))
    2199             ASM_NOTGOOD_BY_ERROR(linePtr, "Expected name of register type")
    2200         skipSpacesToEnd(linePtr, end);
    2201        
    2202         if (linePtr!=end && *linePtr!=',')
    2203         {
    2204             if (*linePtr!=':')
    2205             {
    2206                 asmr.printError(linePtr, "Expected colon after reg-var");
    2207                 continue;
    2208             }
    2209             linePtr++;
    2210             skipSpacesToEnd(linePtr, end);
    2211             uint64_t regSize;
    2212             if (!getAbsoluteValueArg(asmr, regSize, linePtr, true))
    2213                 continue;
    2214             if (regSize==0)
    2215                 ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var is zero")
    2216             if (regSize>UINT16_MAX)
    2217                 ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var out of range")
    2218             var.size = regSize;
    2219         }
    2220        
    2221         if (!good)
    2222             continue;
    2223        
    2224         if (!asmr.addRegVar(name, var))
    2225             asmr.printError(regNamePlace, (std::string("Reg-var '")+name.c_str()+
    2226                         "' was already defined").c_str());
    2227        
    2228     } while(skipCommaForMultipleArgs(asmr, linePtr));
    2229    
    2230     checkGarbagesAtEnd(asmr, linePtr);
    2231 }
    2232 
    2233 void AsmPseudoOps::addCodeFlowEntries(Assembler& asmr, const char* pseudoOpPlace,
    2234                      const char* linePtr, AsmCodeFlowType type)
    2235 {
    2236     const bool acceptArgs = (type==AsmCodeFlowType::JUMP || type==AsmCodeFlowType::CJUMP ||
    2237             type==AsmCodeFlowType::CALL);
    2238     asmr.initializeOutputFormat();
    2239    
    2240     if (asmr.currentSection==ASMSECT_ABS ||
    2241         asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
    2242         PSEUDOOP_RETURN_BY_ERROR("Defining codeflow in non-code section is illegal")
    2243    
    2244     const char* end = asmr.line+asmr.lineSize;
    2245     if (acceptArgs)
    2246     {
    2247         // multiple entries
    2248         do {
    2249             bool good = true;
    2250             skipSpacesToEnd(linePtr, end);
    2251             if (!good)
    2252                 continue;
    2253             std::unique_ptr<AsmExpression> expr;
    2254             uint64_t target;
    2255             if (!getJumpValueArg(asmr, target, expr, linePtr))
    2256                 continue;
    2257             asmr.sections[asmr.currentSection].addCodeFlowEntry({
    2258                     size_t(asmr.currentOutPos), size_t(target), type });
    2259             if (expr)
    2260                 expr->setTarget(AsmExprTarget::codeFlowTarget(asmr.currentSection,
    2261                         asmr.sections[asmr.currentSection].codeFlow.size()-1));
    2262             expr.release();
    2263         } while (skipCommaForMultipleArgs(asmr, linePtr));
    2264     }
    2265     else // single entry without target
    2266         asmr.sections[asmr.currentSection].addCodeFlowEntry({
    2267                     size_t(asmr.currentOutPos), 0, type });
    2268    
    2269     checkGarbagesAtEnd(asmr, linePtr);
    2270 }
    2271 
    2272 // get predefine value ('.get_64bit', '.get_arch', '.get_format')
    2273 void AsmPseudoOps::getPredefinedValue(Assembler& asmr, const char* linePtr,
    2274                             AsmPredefined predefined)
    2275 {
    2276     cxuint predefValue = 0;
    2277     // we must initialize output format before getting any arch, gpu or format
    2278     // must be set before
    2279     asmr.initializeOutputFormat();
    2280     switch (predefined)
    2281     {
    2282         case AsmPredefined::ARCH:
    2283             predefValue = cxuint(getGPUArchitectureFromDeviceType(asmr.deviceType));
    2284             break;
    2285         case AsmPredefined::BIT64:
    2286             predefValue = asmr._64bit;
    2287             break;
    2288         case AsmPredefined::GPU:
    2289             predefValue = cxuint(asmr.deviceType);
    2290             break;
    2291         case AsmPredefined::FORMAT:
    2292             predefValue = cxuint(asmr.format);
    2293             break;
    2294         case AsmPredefined::VERSION:
    2295             predefValue = CLRX_VERSION_NUMBER;
    2296             break;
    2297         case AsmPredefined::POLICY:
    2298             predefValue = asmr.policyVersion;
    2299             break;
    2300         default:
    2301             break;
    2302     }
    2303     AsmParseUtils::setSymbolValue(asmr, linePtr, predefValue, ASMSECT_ABS);
    2304 }
    2305 
    2306 void AsmPseudoOps::doEnum(Assembler& asmr, const char* linePtr)
    2307 {
    2308     const char* end = asmr.line + asmr.lineSize;
    2309     skipSpacesToEnd(linePtr, end);
    2310     uint64_t& enumCount = asmr.currentScope->enumCount;
    2311     if (linePtr!=end && *linePtr=='>')
    2312     {
    2313         // parse enum start
    2314         linePtr++;
    2315         uint64_t enumStart = 0;
    2316         if (!getAbsoluteValueArg(asmr, enumStart, linePtr, false))
    2317             return;
    2318        
    2319         enumCount = enumStart;
    2320         if (!skipRequiredComma(asmr, linePtr))
    2321             return;
    2322     }
    2323     skipSpacesToEnd(linePtr, end);
    2324     do {
    2325         const char* strAtSymName = linePtr;
    2326         CString symbolName = extractScopedSymName(linePtr, end, false);
    2327         if (!symbolName.empty())
    2328         {
    2329             std::pair<AsmSymbolEntry*, bool> res =
    2330                     asmr.insertSymbolInScope(symbolName, AsmSymbol());
    2331             if (!res.second && res.first->second.isDefined())
    2332                 // found and can be only once defined
    2333                 asmr.printError(strAtSymName, (std::string("Symbol '") +
    2334                         symbolName.c_str() + "' is already defined").c_str());
    2335             else
    2336             {
    2337                 asmr.setSymbol(*res.first, enumCount++, ASMSECT_ABS);
    2338                 res.first->second.onceDefined = true;
    2339             }
    2340         }
    2341         else
    2342             asmr.printError(linePtr, "Expected symbol name");
    2343        
    2344     } while(skipCommaForMultipleArgs(asmr, linePtr));
    2345     checkGarbagesAtEnd(asmr, linePtr);
    2346 }
    2347 
    2348 void AsmPseudoOps::setPolicyVersion(Assembler& asmr, const char* linePtr)
    2349 {
    2350     const char* end = asmr.line + asmr.lineSize;
    2351     skipSpacesToEnd(linePtr, end);
    2352     uint64_t value = 0;
    2353     skipSpacesToEnd(linePtr, end);
    2354     const char* valuePlace = linePtr;
    2355     if (!getAbsoluteValueArg(asmr, value, linePtr, true))
    2356         return;
    2357     if (!checkGarbagesAtEnd(asmr, linePtr))
    2358         return;
    2359    
    2360     asmr.printWarningForRange(sizeof(cxuint)*8, value,
    2361                     asmr.getSourcePos(valuePlace), WS_UNSIGNED);
    2362     asmr.setPolicyVersion(value);
    2363 }
    2364 
    2365 void AsmPseudoOps::ignoreString(Assembler& asmr, const char* linePtr)
    2366 {
    2367     const char* end = asmr.line+asmr.lineSize;
    2368     skipSpacesToEnd(linePtr, end);
    2369     std::string out;
    2370     if (asmr.parseString(out, linePtr))
    2371         checkGarbagesAtEnd(asmr, linePtr);
    2372 }
    2373 
    2374173// checking whether name is pseudo-op name
    2375174// (checking any extra pseudo-op provided by format handler)
     
    2395194
    2396195};
     196
    2397197
    2398198void Assembler::parsePseudoOps(const CString& firstName,
  • CLRadeonExtender/trunk/amdasm/CMakeLists.txt

    r4135 r4136  
    2727        AsmGalliumFormat.cpp
    2828        AsmPseudoOps.cpp
     29        AsmPseudoOpsCode1.cpp
    2930        AsmROCmFormat.cpp
    3031        AsmRegAlloc.cpp
Note: See TracChangeset for help on using the changeset viewer.