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

Last change on this file since 4172 was 4172, checked in by matszpk, 11 months ago

CLRadeonExtender: AsmRegAlloc?: Unfinished integration LinearDepHandler? with AsmRegAllocator?.

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