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

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

CLRadeonExtender: AsmRegAlloc?: preps to creating livenesses with routines.

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