source: CLRX/CLRadeonExtender/trunk/CLRX/amdasm/Assembler.h @ 3997

Last change on this file since 3997 was 3997, checked in by matszpk, 12 months ago

CLRadeonExtender: AsmRegAlloc?: First testcase for AsmRegAlloc::applySSAReplaces routine. Add new constructor to AsmRegAllocator? (to simplify testing).
Add new constructor to VectoSet?.

File size: 30.8 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19/*! \file Assembler.h
20 * \brief an assembler for Radeon GPU's
21 */
22
23#ifndef __CLRX_ASSEMBLER_H__
24#define __CLRX_ASSEMBLER_H__
25
26#include <CLRX/Config.h>
27#include <cstdint>
28#include <string>
29#include <istream>
30#include <ostream>
31#include <iostream>
32#include <vector>
33#include <utility>
34#include <stack>
35#include <list>
36#include <unordered_set>
37#include <unordered_map>
38#include <CLRX/utils/Utilities.h>
39#include <CLRX/utils/Containers.h>
40#include <CLRX/amdasm/Commons.h>
41#include <CLRX/amdasm/AsmSource.h>
42#include <CLRX/amdasm/AsmFormats.h>
43#include <CLRX/amdasm/AsmDefs.h>
44
45/// main namespace
46namespace CLRX
47{
48
49enum: Flags
50{
51    ASM_WARNINGS = 1,   ///< enable all warnings for assembler
52    ASM_FORCE_ADD_SYMBOLS = 2,  ///< force add symbols to binary
53    ASM_ALTMACRO = 4,   ///< enable altmacro mode
54    ASM_BUGGYFPLIT = 8, ///< buggy handling of fpliterals (including fp constants)
55    ASM_MACRONOCASE = 16, /// disable case-insensitive naming (default)
56    ASM_OLDMODPARAM = 32,   ///< use old modifier parametrization (values 0 and 1 only)
57    ASM_TESTRESOLVE = (1U<<30), ///< enable resolving symbols if ASM_TESTRUN enabled
58    ASM_TESTRUN = (1U<<31), ///< only for running tests
59    ASM_ALL = FLAGS_ALL&~(ASM_TESTRUN|ASM_TESTRESOLVE|ASM_BUGGYFPLIT|ASM_MACRONOCASE|
60                    ASM_OLDMODPARAM)  ///< all flags
61};
62
63struct AsmRegVar;
64
65/// ISA (register and regvar) Usage handler
66class ISAUsageHandler
67{
68public:
69    /// stgructure that hold read position to store later
70    struct ReadPos
71    {
72        size_t readOffset;  ///< read offset
73        size_t instrStructPos;  ///< position instrStructs
74        size_t regUsagesPos;    ///< position in reg usage
75        size_t regUsages2Pos;   ///< position in regUsage2
76        size_t regVarUsagesPos;    ///< position in regVarUsage
77        uint16_t pushedArgs;    ///< pushed argds number
78        bool useRegMode;        ///< true if in usereg mode
79    };
80protected:
81    std::vector<cxbyte> instrStruct;    ///< structure of register usage
82    std::vector<AsmRegUsageInt> regUsages;  ///< register usage
83    std::vector<AsmRegUsage2Int> regUsages2;  ///< register usage (by .usereg)
84    std::vector<AsmRegVarUsageInt> regVarUsages;    ///< regvar usage
85    const std::vector<cxbyte>& content; ///< code content
86    size_t lastOffset;  ///< last offset
87    size_t readOffset;  ///< read offset
88    size_t instrStructPos;  ///< position in instr struct
89    size_t regUsagesPos;    ///< position in reg usage
90    size_t regUsages2Pos;   ///< position in reg usage 2
91    size_t regVarUsagesPos; ///< position in regvar usage
92    uint16_t pushedArgs;    ///< pushed args
93    cxbyte argPos;      ///< argument position
94    cxbyte argFlags;    ///< ???
95    cxbyte defaultInstrSize;    ///< default instruction size
96    bool isNext;        ///< is next
97    bool useRegMode;    ///< true if in usereg mode
98   
99    void skipBytesInInstrStruct();
100    /// put space to offset
101    void putSpace(size_t offset);
102   
103    /// constructor
104    explicit ISAUsageHandler(const std::vector<cxbyte>& content);
105public:
106    /// destructor
107    virtual ~ISAUsageHandler();
108    /// copy this usage handler
109    virtual ISAUsageHandler* copy() const = 0;
110   
111    /// push regvar or register usage
112    void pushUsage(const AsmRegVarUsage& rvu);
113    /// rewind to start for reading
114    void rewind();
115    /// flush last pending register usages
116    void flush();
117    /// has next regvar usage
118    bool hasNext() const
119    { return isNext; }
120    /// get next usage
121    AsmRegVarUsage nextUsage();
122   
123    /// get reading position
124    ReadPos getReadPos() const
125    {
126        return { readOffset, instrStructPos, regUsagesPos, regUsages2Pos,
127            regVarUsagesPos, pushedArgs, useRegMode };
128    }
129    /// set reading position
130    void setReadPos(const ReadPos rpos)
131    {
132        readOffset = rpos.readOffset;
133        instrStructPos = rpos.instrStructPos;
134        regUsagesPos = rpos.regUsagesPos;
135        regUsages2Pos = rpos.regUsages2Pos;
136        regVarUsagesPos = rpos.regVarUsagesPos;
137        pushedArgs = rpos.pushedArgs;
138        useRegMode = rpos.useRegMode;
139    }
140   
141    /// push regvar or register from usereg pseudo-op
142    void pushUseRegUsage(const AsmRegVarUsage& rvu);
143   
144    /// get RW flags (used by assembler)
145    virtual cxbyte getRwFlags(AsmRegField regField, uint16_t rstart,
146                      uint16_t rend) const = 0;
147    /// get reg pair (used by assembler)
148    virtual std::pair<uint16_t,uint16_t> getRegPair(AsmRegField regField,
149                    cxbyte rwFlags) const = 0;
150    /// get usage dependencies around single instruction
151    virtual void getUsageDependencies(cxuint rvusNum, const AsmRegVarUsage* rvus,
152                    cxbyte* linearDeps, cxbyte* equalToDeps) const = 0;
153};
154
155/// GCN (register and regvar) Usage handler
156class GCNUsageHandler: public ISAUsageHandler
157{
158private:
159    uint16_t archMask;
160public:
161    /// constructor
162    GCNUsageHandler(const std::vector<cxbyte>& content, uint16_t archMask);
163    /// destructor
164    ~GCNUsageHandler();
165   
166    /// copy this usage handler
167    ISAUsageHandler* copy() const;
168   
169    cxbyte getRwFlags(AsmRegField regFied, uint16_t rstart, uint16_t rend) const;
170    std::pair<uint16_t,uint16_t> getRegPair(AsmRegField regField, cxbyte rwFlags) const;
171    void getUsageDependencies(cxuint rvusNum, const AsmRegVarUsage* rvus,
172                    cxbyte* linearDeps, cxbyte* equalToDeps) const;
173};
174
175/// ISA assembler class
176class ISAAssembler: public NonCopyableAndNonMovable
177{
178protected:
179    Assembler& assembler;       ///< assembler
180   
181    /// print warning for position pointed by line pointer
182    void printWarning(const char* linePtr, const char* message);
183    /// print error for position pointed by line pointer
184    void printError(const char* linePtr, const char* message);
185    /// print warning for source position
186    void printWarning(const AsmSourcePos& sourcePos, const char* message);
187    /// print error for source position
188    void printError(const AsmSourcePos& sourcePos, const char* message);
189    /// print warning about integer out of range
190    void printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
191                cxbyte signess = WS_BOTH);
192    void addCodeFlowEntry(cxuint sectionId, const AsmCodeFlowEntry& entry);
193    /// constructor
194    explicit ISAAssembler(Assembler& assembler);
195public:
196    /// destructor
197    virtual ~ISAAssembler();
198    /// create usage handler
199    virtual ISAUsageHandler* createUsageHandler(std::vector<cxbyte>& content) const = 0;
200   
201    /// assemble single line
202    virtual void assemble(const CString& mnemonic, const char* mnemPlace,
203              const char* linePtr, const char* lineEnd, std::vector<cxbyte>& output,
204              ISAUsageHandler* usageHandler) = 0;
205    /// resolve code with location, target and value
206    virtual bool resolveCode(const AsmSourcePos& sourcePos, cxuint targetSectionId,
207                 cxbyte* sectionData, size_t offset, AsmExprTargetType targetType,
208                 cxuint sectionId, uint64_t value) = 0;
209    /// check if name is mnemonic
210    virtual bool checkMnemonic(const CString& mnemonic) const = 0;
211    /// set allocated registers (if regs is null then reset them)
212    virtual void setAllocatedRegisters(const cxuint* regs = nullptr,
213                Flags regFlags = 0) = 0;
214    /// get allocated register numbers after assemblying
215    virtual const cxuint* getAllocatedRegisters(size_t& regTypesNum,
216                Flags& regFlags) const = 0;
217    /// get max registers number
218    virtual void getMaxRegistersNum(size_t& regTypesNum, cxuint* maxRegs) const = 0;
219    /// get registers ranges
220    virtual void getRegisterRanges(size_t& regTypesNum, cxuint* regRanges) const = 0;
221    /// fill alignment when value is not given
222    virtual void fillAlignment(size_t size, cxbyte* output) = 0;
223    /// parse register range
224    virtual bool parseRegisterRange(const char*& linePtr, cxuint& regStart,
225                        cxuint& regEnd, const AsmRegVar*& regVar) = 0;
226    /// return true if expresion of target fit to value with specified bits
227    virtual bool relocationIsFit(cxuint bits, AsmExprTargetType tgtType) = 0;
228    /// parse register type for '.reg' pseudo-op
229    virtual bool parseRegisterType(const char*& linePtr,
230                       const char* end, cxuint& type) = 0;
231    /// get size of instruction
232    virtual size_t getInstructionSize(size_t codeSize, const cxbyte* code) const = 0;
233};
234
235/// GCN arch assembler
236class GCNAssembler: public ISAAssembler
237{
238public:
239    /// register pool numbers
240    struct Regs {
241        cxuint sgprsNum;    ///< SGPRs number
242        cxuint vgprsNum;    ///< VGPRs number
243        Flags regFlags; ///< define what extra register must be included
244    };
245private:
246    friend struct GCNAsmUtils; // INTERNAL LOGIC
247    union {
248        Regs regs;
249        cxuint regTable[2];
250    };
251    uint16_t curArchMask;
252    cxbyte currentRVUIndex;
253    AsmRegVarUsage instrRVUs[6];
254   
255    void resetInstrRVUs()
256    {
257        for (AsmRegVarUsage& rvu: instrRVUs)
258            rvu.regField = ASMFIELD_NONE;
259    }
260    void setCurrentRVU(cxbyte idx)
261    { currentRVUIndex = idx; }
262   
263    void setRegVarUsage(const AsmRegVarUsage& rvu)
264    { instrRVUs[currentRVUIndex] = rvu; }
265   
266    void flushInstrRVUs(ISAUsageHandler* usageHandler)
267    {
268        for (const AsmRegVarUsage& rvu: instrRVUs)
269            if (rvu.regField != ASMFIELD_NONE)
270                usageHandler->pushUsage(rvu);
271    }
272public:
273    /// constructor
274    explicit GCNAssembler(Assembler& assembler);
275    /// destructor
276    ~GCNAssembler();
277   
278    ISAUsageHandler* createUsageHandler(std::vector<cxbyte>& content) const;
279   
280    void assemble(const CString& mnemonic, const char* mnemPlace, const char* linePtr,
281                  const char* lineEnd, std::vector<cxbyte>& output,
282                  ISAUsageHandler* usageHandler);
283    bool resolveCode(const AsmSourcePos& sourcePos, cxuint targetSectionId,
284                 cxbyte* sectionData, size_t offset, AsmExprTargetType targetType,
285                 cxuint sectionId, uint64_t value);
286    bool checkMnemonic(const CString& mnemonic) const;
287    void setAllocatedRegisters(const cxuint* regs, Flags regFlags);
288    const cxuint* getAllocatedRegisters(size_t& regTypesNum, Flags& regFlags) const;
289    void getMaxRegistersNum(size_t& regTypesNum, cxuint* maxRegs) const;
290    void getRegisterRanges(size_t& regTypesNum, cxuint* regRanges) const;
291    void fillAlignment(size_t size, cxbyte* output);
292    bool parseRegisterRange(const char*& linePtr, cxuint& regStart, cxuint& regEnd,
293                const AsmRegVar*& regVar);
294    bool relocationIsFit(cxuint bits, AsmExprTargetType tgtType);
295    bool parseRegisterType(const char*& linePtr, const char* end, cxuint& type);
296    size_t getInstructionSize(size_t codeSize, const cxbyte* code) const;
297};
298
299class AsmRegAllocator
300{
301public:
302    struct NextBlock
303    {
304        size_t block;
305        bool isCall;
306    };
307    struct SSAInfo
308    {
309        size_t ssaIdBefore; ///< SSA id before first SSA in block
310        size_t ssaIdFirst; // SSA id at first change
311        size_t ssaId;   ///< original SSA id
312        size_t ssaIdLast; ///< last SSA id in last
313        size_t ssaIdChange; ///< number of SSA id changes
314        size_t firstPos;
315        size_t lastPos;
316        bool readBeforeWrite;   ///< have read before write
317        SSAInfo(size_t _bssaId = SIZE_MAX, size_t _ssaIdF = SIZE_MAX,
318                size_t _ssaId = SIZE_MAX, size_t _ssaIdL = SIZE_MAX,
319                size_t _ssaIdChange = 0, bool _readBeforeWrite = false)
320            : ssaIdBefore(_bssaId), ssaIdFirst(_ssaIdF), ssaId(_ssaId),
321              ssaIdLast(_ssaIdL), ssaIdChange(_ssaIdChange),
322              readBeforeWrite(_readBeforeWrite)
323        { }
324    };
325    struct CodeBlock
326    {
327        size_t start, end; // place in code
328        std::vector<NextBlock> nexts; ///< nexts blocks, if empty then direct next block
329        bool haveCalls;
330        bool haveReturn;
331        bool haveEnd;
332        // key - regvar, value - SSA info for this regvar
333        std::unordered_map<AsmSingleVReg, SSAInfo> ssaInfoMap;
334        ISAUsageHandler::ReadPos usagePos;
335    };
336   
337     // first - orig ssaid, second - dest ssaid
338    typedef std::pair<size_t, size_t> SSAReplace;
339    typedef std::unordered_map<AsmSingleVReg, VectorSet<SSAReplace> > SSAReplacesMap;
340    // interference graph type
341    typedef Array<std::unordered_set<size_t> > InterGraph;
342    typedef std::unordered_map<AsmSingleVReg, std::vector<size_t> > VarIndexMap;
343    struct LinearDep
344    {
345        cxbyte align;
346        std::vector<size_t> prevVidxes;
347        std::vector<size_t> nextVidxes;
348    };
349    struct EqualToDep
350    {
351        std::vector<size_t> prevVidxes;
352        std::vector<size_t> nextVidxes;
353    };
354private:
355    Assembler& assembler;
356    std::vector<CodeBlock> codeBlocks;
357    SSAReplacesMap ssaReplacesMap;
358    size_t regTypesNum;
359   
360    VarIndexMap vregIndexMaps[MAX_REGTYPES_NUM]; // indices to igraph for 2 reg types
361    InterGraph interGraphs[MAX_REGTYPES_NUM]; // for 2 register
362    Array<cxuint> graphColorMaps[MAX_REGTYPES_NUM];
363    std::unordered_map<size_t, LinearDep> linearDepMaps[MAX_REGTYPES_NUM];
364    std::unordered_map<size_t, EqualToDep> equalToDepMaps[MAX_REGTYPES_NUM];
365    std::unordered_map<size_t, size_t> equalSetMaps[MAX_REGTYPES_NUM];
366    std::vector<std::vector<size_t> > equalSetLists[MAX_REGTYPES_NUM];
367   
368public:
369    AsmRegAllocator(Assembler& assembler);
370    // constructor for testing
371    AsmRegAllocator(Assembler& assembler, const std::vector<CodeBlock>& codeBlocks,
372                const SSAReplacesMap& ssaReplacesMap);
373   
374    void createCodeStructure(const std::vector<AsmCodeFlowEntry>& codeFlow,
375             size_t codeSize, const cxbyte* code);
376    void createSSAData(ISAUsageHandler& usageHandler);
377    void applySSAReplaces();
378    void createInterferenceGraph(ISAUsageHandler& usageHandler);
379    void colorInterferenceGraph();
380   
381    void allocateRegisters(cxuint sectionId);
382   
383    const std::vector<CodeBlock>& getCodeBlocks() const
384    { return codeBlocks; }
385    const SSAReplacesMap& getSSAReplacesMap() const
386    { return ssaReplacesMap; }
387};
388
389/// type of clause
390enum class AsmClauseType
391{
392    IF,     ///< if clause
393    ELSEIF, ///< elseif clause
394    ELSE,   ///< else clause
395    REPEAT, ///< rept clause or irp/irpc clause
396    MACRO   ///< macro clause
397};
398
399/// assembler's clause (if,else,macro,rept)
400struct AsmClause
401{
402    AsmClauseType type; ///< type of clause
403    AsmSourcePos sourcePos;   ///< position in source code
404    bool condSatisfied; ///< if conditional clause has already been satisfied
405    AsmSourcePos prevIfPos; ///< position of previous if-clause
406};
407
408/// main class of assembler
409class Assembler: public NonCopyableAndNonMovable
410{
411public:
412    /// defined symbol entry
413    typedef std::pair<CString, uint64_t> DefSym;
414    /// kernel map type
415    typedef std::unordered_map<CString, cxuint> KernelMap;
416private:
417    friend class AsmStreamInputFilter;
418    friend class AsmMacroInputFilter;
419    friend class AsmForInputFilter;
420    friend class AsmExpression;
421    friend class AsmFormatHandler;
422    friend class AsmRawCodeHandler;
423    friend class AsmAmdHandler;
424    friend class AsmAmdCL2Handler;
425    friend class AsmGalliumHandler;
426    friend class AsmROCmHandler;
427    friend class ISAAssembler;
428    friend class AsmRegAllocator;
429   
430    friend struct AsmParseUtils; // INTERNAL LOGIC
431    friend struct AsmPseudoOps; // INTERNAL LOGIC
432    friend struct AsmGalliumPseudoOps; // INTERNAL LOGIC
433    friend struct AsmAmdPseudoOps; // INTERNAL LOGIC
434    friend struct AsmAmdCL2PseudoOps; // INTERNAL LOGIC
435    friend struct AsmROCmPseudoOps; // INTERNAL LOGIC
436    friend struct GCNAsmUtils; // INTERNAL LOGIC
437
438    Array<CString> filenames;
439    BinaryFormat format;
440    GPUDeviceType deviceType;
441    uint32_t driverVersion;
442    uint32_t llvmVersion; // GalliumCompute
443    bool _64bit;    ///
444    bool newROCmBinFormat;
445    bool good;
446    bool resolvingRelocs;
447    bool doNotRemoveFromSymbolClones;
448    ISAAssembler* isaAssembler;
449    std::vector<DefSym> defSyms;
450    std::vector<CString> includeDirs;
451    std::vector<AsmSection> sections;
452    std::vector<Array<cxuint> > relSpacesSections;
453    std::unordered_set<AsmSymbolEntry*> symbolSnapshots;
454    std::unordered_set<AsmSymbolEntry*> symbolClones;
455    std::vector<AsmExpression*> unevalExpressions;
456    std::vector<AsmRelocation> relocations;
457    AsmScope globalScope;
458    AsmMacroMap macroMap;
459    std::stack<AsmScope*> scopeStack;
460    std::vector<AsmScope*> abandonedScopes;
461    AsmScope* currentScope;
462    KernelMap kernelMap;
463    std::vector<AsmKernel> kernels;
464    /// register variables
465    Flags flags;
466    uint64_t macroCount;
467    uint64_t localCount; // macro's local count
468    bool alternateMacro;
469    bool buggyFPLit;
470    bool macroCase;
471    bool oldModParam;
472   
473    cxuint inclusionLevel;
474    cxuint macroSubstLevel;
475    cxuint repetitionLevel;
476    bool lineAlreadyRead; // if line already read
477   
478    size_t lineSize;
479    const char* line;
480    bool endOfAssembly;
481    bool sectionDiffsPrepared;
482   
483    cxuint filenameIndex;
484    std::stack<AsmInputFilter*> asmInputFilters;
485    AsmInputFilter* currentInputFilter;
486   
487    std::ostream& messageStream;
488    std::ostream& printStream;
489   
490    AsmFormatHandler* formatHandler;
491   
492    std::stack<AsmClause> clauses;
493   
494    cxuint currentKernel;
495    cxuint& currentSection;
496    uint64_t& currentOutPos;
497   
498    bool withSectionDiffs() const
499    { return formatHandler!=nullptr && formatHandler->isSectionDiffsResolvable(); }
500   
501    AsmSourcePos getSourcePos(LineCol lineCol) const
502    {
503        return { currentInputFilter->getMacroSubst(), currentInputFilter->getSource(),
504            lineCol.lineNo, lineCol.colNo };
505    }
506   
507    AsmSourcePos getSourcePos(size_t pos) const
508    { return currentInputFilter->getSourcePos(pos); }
509    AsmSourcePos getSourcePos(const char* linePtr) const
510    { return getSourcePos(linePtr-line); }
511   
512    void printWarning(const AsmSourcePos& pos, const char* message);
513    void printError(const AsmSourcePos& pos, const char* message);
514   
515    void printWarning(const char* linePtr, const char* message)
516    { printWarning(getSourcePos(linePtr), message); }
517    void printError(const char* linePtr, const char* message)
518    { printError(getSourcePos(linePtr), message); }
519   
520    void printWarning(LineCol lineCol, const char* message)
521    { printWarning(getSourcePos(lineCol), message); }
522    void printError(LineCol lineCol, const char* message)
523    { printError(getSourcePos(lineCol), message); }
524   
525    LineCol translatePos(const char* linePtr) const
526    { return currentInputFilter->translatePos(linePtr-line); }
527    LineCol translatePos(size_t pos) const
528    { return currentInputFilter->translatePos(pos); }
529   
530    bool parseLiteral(uint64_t& value, const char*& linePtr);
531    bool parseLiteralNoError(uint64_t& value, const char*& linePtr);
532    bool parseString(std::string& outString, const char*& linePtr);
533   
534    enum class ParseState
535    {
536        FAILED = 0,
537        PARSED,
538        MISSING // missing element
539    };
540   
541    /** parse symbol
542     * \return state
543     */
544    ParseState parseSymbol(const char*& linePtr, AsmSymbolEntry*& entry,
545                   bool localLabel = true, bool dontCreateSymbol = false);
546    bool skipSymbol(const char*& linePtr);
547   
548    bool setSymbol(AsmSymbolEntry& symEntry, uint64_t value, cxuint sectionId);
549   
550    bool assignSymbol(const CString& symbolName, const char* symbolPlace,
551                  const char* linePtr, bool reassign = true, bool baseExpr = false);
552   
553    bool assignOutputCounter(const char* symbolPlace, uint64_t value, cxuint sectionId,
554                     cxbyte fillValue = 0);
555   
556    void parsePseudoOps(const CString& firstName, const char* stmtPlace,
557                const char* linePtr);
558   
559    /// exitm - exit macro mode
560    bool skipClauses(bool exitm = false);
561    bool putMacroContent(RefPtr<AsmMacro> macro);
562    bool putRepetitionContent(AsmRepeat& repeat);
563   
564    void initializeOutputFormat();
565   
566    bool pushClause(const char* string, AsmClauseType clauseType)
567    {
568        bool included; // to ignore
569        return pushClause(string, clauseType, true, included);
570    }
571    bool pushClause(const char* string, AsmClauseType clauseType,
572                  bool satisfied, bool& included);
573     // return false when failed (for example no clauses)
574    bool popClause(const char* string, AsmClauseType clauseType);
575   
576    // recursive function to find scope in scope
577    AsmScope* findScopeInScope(AsmScope* scope, const CString& scopeName,
578                    std::unordered_set<AsmScope*>& scopeSet);
579    // find scope by identifier
580    AsmScope* getRecurScope(const CString& scopePlace, bool ignoreLast = false,
581                    const char** lastStep = nullptr);
582    // find symbol in scopes
583    // internal recursive function to find symbol in scope
584    AsmSymbolEntry* findSymbolInScopeInt(AsmScope* scope, const CString& symName,
585                    std::unordered_set<AsmScope*>& scopeSet);
586    // scope - return scope from scoped name
587    AsmSymbolEntry* findSymbolInScope(const CString& symName, AsmScope*& scope,
588                      CString& sameSymName, bool insertMode = false);
589    // similar to map::insert, but returns pointer
590    std::pair<AsmSymbolEntry*, bool> insertSymbolInScope(const CString& symName,
591                 const AsmSymbol& symbol);
592   
593    // internal recursive function to find symbol in scope
594    AsmRegVarEntry* findRegVarInScopeInt(AsmScope* scope, const CString& rvName,
595                    std::unordered_set<AsmScope*>& scopeSet);
596    // scope - return scope from scoped name
597    AsmRegVarEntry* findRegVarInScope(const CString& rvName, AsmScope*& scope,
598                      CString& sameRvName, bool insertMode = false);
599    // similar to map::insert, but returns pointer
600    std::pair<AsmRegVarEntry*, bool> insertRegVarInScope(const CString& rvName,
601                 const AsmRegVar& regVar);
602   
603    // create scope
604    bool getScope(AsmScope* parent, const CString& scopeName, AsmScope*& scope);
605    // push new scope level
606    bool pushScope(const CString& scopeName);
607    bool popScope();
608   
609    /// returns false when includeLevel is too deep, throw error if failed a file opening
610    bool includeFile(const char* pseudoOpPlace, const std::string& filename);
611   
612    ParseState makeMacroSubstitution(const char* string);
613   
614    bool parseMacroArgValue(const char*& linePtr, std::string& outStr);
615   
616    void putData(size_t size, const cxbyte* data)
617    {
618        AsmSection& section = sections[currentSection];
619        section.content.insert(section.content.end(), data, data+size);
620        currentOutPos += size;
621    }
622   
623    cxbyte* reserveData(size_t size, cxbyte fillValue = 0);
624   
625    void goToMain(const char* pseudoOpPlace);
626    void goToKernel(const char* pseudoOpPlace, const char* kernelName);
627    void goToSection(const char* pseudoOpPlace, const char* sectionName, uint64_t align=0);
628    void goToSection(const char* pseudoOpPlace, const char* sectionName,
629                     AsmSectionType type, Flags flags, uint64_t align=0);
630    void goToSection(const char* pseudoOpPlace, cxuint sectionId, uint64_t align=0);
631   
632    void printWarningForRange(cxuint bits, uint64_t value, const AsmSourcePos& pos,
633                  cxbyte signess = WS_BOTH);
634   
635    bool isAddressableSection() const
636    {
637        return currentSection==ASMSECT_ABS ||
638                    (sections[currentSection].flags & ASMSECT_ADDRESSABLE) != 0;
639    }
640    bool isWriteableSection() const
641    {
642        return currentSection!=ASMSECT_ABS &&
643                (sections[currentSection].flags & ASMSECT_WRITEABLE) != 0;
644    }
645    bool isResolvableSection() const
646    {
647        return currentSection==ASMSECT_ABS ||
648                (sections[currentSection].flags & ASMSECT_UNRESOLVABLE) == 0;
649    }
650    bool isResolvableSection(cxuint sectionId) const
651    {
652        return sectionId==ASMSECT_ABS ||
653                (sections[sectionId].flags & ASMSECT_UNRESOLVABLE) == 0;
654    }
655   
656    // oldKernels and newKernels must be sorted
657    void handleRegionsOnKernels(const std::vector<cxuint>& newKernels,
658                const std::vector<cxuint>& oldKernels, cxuint codeSection);
659   
660    void tryToResolveSymbol(AsmSymbolEntry& symEntry);
661    void tryToResolveSymbols(AsmScope* scope);
662    void printUnresolvedSymbols(AsmScope* scope);
663   
664    bool resolveExprTarget(const AsmExpression* expr, uint64_t value, cxuint sectionId);
665   
666    void cloneSymEntryIfNeeded(AsmSymbolEntry& symEntry);
667   
668    void undefineSymbol(AsmSymbolEntry& symEntry);
669   
670protected:
671    /// helper for testing
672    bool readLine();
673public:
674    /// constructor with filename and input stream
675    /**
676     * \param filename filename
677     * \param input input stream
678     * \param flags assembler flags
679     * \param format output format type
680     * \param deviceType GPU device type
681     * \param msgStream stream for warnings and errors
682     * \param printStream stream for printing message by .print pseudo-ops
683     */
684    explicit Assembler(const CString& filename, std::istream& input, Flags flags = 0,
685              BinaryFormat format = BinaryFormat::AMD,
686              GPUDeviceType deviceType = GPUDeviceType::CAPE_VERDE,
687              std::ostream& msgStream = std::cerr, std::ostream& printStream = std::cout);
688   
689    /// constructor with filename and input stream
690    /**
691     * \param filenames filenames
692     * \param flags assembler flags
693     * \param format output format type
694     * \param deviceType GPU device type
695     * \param msgStream stream for warnings and errors
696     * \param printStream stream for printing message by .print pseudo-ops
697     */
698    explicit Assembler(const Array<CString>& filenames, Flags flags = 0,
699              BinaryFormat format = BinaryFormat::AMD,
700              GPUDeviceType deviceType = GPUDeviceType::CAPE_VERDE,
701              std::ostream& msgStream = std::cerr, std::ostream& printStream = std::cout);
702    /// destructor
703    ~Assembler();
704   
705    /// main routine to assemble code
706    bool assemble();
707   
708    /// write binary to file
709    void writeBinary(const char* filename) const;
710    /// write binary to stream
711    void writeBinary(std::ostream& outStream) const;
712    /// write binary to array
713    void writeBinary(Array<cxbyte>& array) const;
714   
715    /// get AMD driver version
716    uint32_t getDriverVersion() const
717    { return driverVersion; }
718    /// set AMD driver version
719    void setDriverVersion(uint32_t driverVersion)
720    { this->driverVersion = driverVersion; }
721   
722    /// get LLVM version
723    uint32_t getLLVMVersion() const
724    { return llvmVersion; }
725    /// set LLVM version
726    void setLLVMVersion(uint32_t llvmVersion)
727    { this->llvmVersion = llvmVersion; }
728   
729    /// get GPU device type
730    GPUDeviceType getDeviceType() const
731    { return deviceType; }
732    /// set GPU device type
733    void setDeviceType(const GPUDeviceType deviceType)
734    { this->deviceType = deviceType; }
735    /// get binary format
736    BinaryFormat getBinaryFormat() const
737    { return format; }
738    /// set binary format
739    void setBinaryFormat(BinaryFormat binFormat)
740    { format = binFormat; }
741    /// get bitness (true if 64-bit)
742    bool is64Bit() const
743    { return _64bit; }
744    /// set bitness (true if 64-bit)
745    void set64Bit(bool this64Bit)
746    {  _64bit = this64Bit; }
747    /// is new ROCm binary format
748    bool isNewROCmBinFormat() const
749    { return newROCmBinFormat; }
750    /// set new ROCm binary format
751    void setNewROCmBinFormat(bool newFmt)
752    { newROCmBinFormat = newFmt; }
753    /// get flags
754    Flags getFlags() const
755    { return flags; }
756    /// set flags
757    void setFlags(Flags flags)
758    { this->flags = flags; }
759    /// get true if altMacro enabled
760    bool isAltMacro() const
761    { return alternateMacro; }
762    /// get true if macroCase enabled
763    bool isMacroCase() const
764    { return macroCase; }
765    /// get true if oldModParam enabled (old modifier parametrization)
766    bool isOldModParam() const
767    { return oldModParam; }
768    /// get true if buggyFPLit enabled
769    bool isBuggyFPLit() const
770    { return buggyFPLit; }
771    /// get include directory list
772    const std::vector<CString>& getIncludeDirs() const
773    { return includeDirs; }
774    /// adds include directory
775    void addIncludeDir(const CString& includeDir);
776    /// get symbols map
777    const AsmSymbolMap& getSymbolMap() const
778    { return globalScope.symbolMap; }
779    /// get sections
780    const std::vector<AsmSection>& getSections() const
781    { return sections; }
782    // get first sections for rel spaces
783    const std::vector<Array<cxuint> >& getRelSpacesSections() const
784    { return relSpacesSections; }
785    /// get kernel map
786    const KernelMap& getKernelMap() const
787    { return kernelMap; }
788    /// get kernels
789    const std::vector<AsmKernel>& getKernels() const
790    { return kernels; }
791    /// get regvar map
792    const AsmRegVarMap& getRegVarMap() const
793    { return globalScope.regVarMap; }
794    /// add regvar
795    bool addRegVar(const CString& name, const AsmRegVar& var)
796    { return insertRegVarInScope(name, var).second; }
797    /// get regvar by name
798    bool getRegVar(const CString& name, const AsmRegVar*& regVar);
799   
800    /// get global scope
801    const AsmScope& getGlobalScope() const
802    { return globalScope; }
803   
804    /// returns true if symbol contains absolute value
805    bool isAbsoluteSymbol(const AsmSymbol& symbol) const;
806   
807    /// add initiali defsyms
808    void addInitialDefSym(const CString& symName, uint64_t value);
809   
810    /// get format handler
811    const AsmFormatHandler* getFormatHandler() const
812    { return formatHandler; }
813};
814
815inline void ISAAssembler::printWarning(const char* linePtr, const char* message)
816{ assembler.printWarning(linePtr, message); }
817
818inline void ISAAssembler::printError(const char* linePtr, const char* message)
819{ assembler.printError(linePtr, message); }
820
821inline void ISAAssembler::printWarningForRange(cxuint bits, uint64_t value,
822                   const AsmSourcePos& pos, cxbyte signess)
823{ assembler.printWarningForRange(bits, value, pos, signess); }
824
825inline void ISAAssembler::printWarning(const AsmSourcePos& sourcePos, const char* message)
826{ assembler.printWarning(sourcePos, message); }
827
828inline void ISAAssembler::printError(const AsmSourcePos& sourcePos, const char* message)
829{ assembler.printError(sourcePos, message); }
830
831inline void ISAAssembler::addCodeFlowEntry(cxuint sectionId, const AsmCodeFlowEntry& entry)
832{ assembler.sections[sectionId].addCodeFlowEntry(entry); }
833
834};
835
836#endif
Note: See TracBrowser for help on using the repository browser.