/* * Copyright 2011 Christoph Bumiller * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __NV50_IR_TARGET_H__ #define __NV50_IR_TARGET_H__ #include "codegen/nv50_ir.h" namespace nv50_ir { struct RelocInfo; struct RelocEntry { enum Type { TYPE_CODE, TYPE_BUILTIN, TYPE_DATA }; uint32_t data; uint32_t mask; uint32_t offset; int8_t bitPos; Type type; inline void apply(uint32_t *binary, const RelocInfo *info) const; }; struct RelocInfo { uint32_t codePos; uint32_t libPos; uint32_t dataPos; uint32_t count; RelocEntry entry[0]; }; class CodeEmitter { public: CodeEmitter(const Target *); virtual ~CodeEmitter() { } // returns whether the instruction was encodable and written virtual bool emitInstruction(Instruction *) = 0; virtual uint32_t getMinEncodingSize(const Instruction *) const = 0; void setCodeLocation(void *, uint32_t size); inline void *getCodeLocation() const { return code; } inline uint32_t getCodeSize() const { return codeSize; } bool addReloc(RelocEntry::Type, int w, uint32_t data, uint32_t m, int s); inline void *getRelocInfo() const { return relocInfo; } virtual void prepareEmission(Program *); virtual void prepareEmission(Function *); virtual void prepareEmission(BasicBlock *); void printBinary() const; protected: const Target *targ; uint32_t *code; uint32_t codeSize; uint32_t codeSizeLimit; RelocInfo *relocInfo; }; enum OpClass { OPCLASS_MOVE = 0, OPCLASS_LOAD = 1, OPCLASS_STORE = 2, OPCLASS_ARITH = 3, OPCLASS_SHIFT = 4, OPCLASS_SFU = 5, OPCLASS_LOGIC = 6, OPCLASS_COMPARE = 7, OPCLASS_CONVERT = 8, OPCLASS_ATOMIC = 9, OPCLASS_TEXTURE = 10, OPCLASS_SURFACE = 11, OPCLASS_FLOW = 12, OPCLASS_PSEUDO = 14, OPCLASS_VECTOR = 15, OPCLASS_BITFIELD = 16, OPCLASS_CONTROL = 17, OPCLASS_OTHER = 18 }; class Target { public: Target(bool m, bool j, bool s) : hasJoin(m), joinAnterior(j), hasSWSched(s) { } virtual ~Target() { } static Target *create(uint32_t chipset); static void destroy(Target *); // 0x50 and 0x84 to 0xaf for nv50 // 0xc0 to 0xdf for nvc0 inline uint32_t getChipset() const { return chipset; } virtual CodeEmitter *getCodeEmitter(Program::Type) = 0; // Drivers should upload this so we can use it from all programs. // The address chosen is supplied to the relocation routine. virtual void getBuiltinCode(const uint32_t **code, uint32_t *size) const = 0; virtual void parseDriverInfo(const struct nv50_ir_prog_info *info) { } virtual bool runLegalizePass(Program *, CGStage stage) const = 0; public: struct OpInfo { OpInfo *variants; operation op; uint16_t srcTypes; uint16_t dstTypes; uint32_t immdBits; uint8_t srcNr; uint8_t srcMods[3]; uint8_t dstMods; uint16_t srcFiles[3]; uint16_t dstFiles; unsigned int minEncSize : 4; unsigned int vector : 1; unsigned int predicate : 1; unsigned int commutative : 1; unsigned int pseudo : 1; unsigned int flow : 1; unsigned int hasDest : 1; unsigned int terminator : 1; }; inline const OpInfo& getOpInfo(const Instruction *) const; inline const OpInfo& getOpInfo(const operation) const; inline DataFile nativeFile(DataFile f) const; virtual bool insnCanLoad(const Instruction *insn, int s, const Instruction *ld) const = 0; virtual bool isOpSupported(operation, DataType) const = 0; virtual bool isAccessSupported(DataFile, DataType) const = 0; virtual bool isModSupported(const Instruction *, int s, Modifier) const = 0; virtual bool isSatSupported(const Instruction *) const = 0; virtual bool isPostMultiplySupported(operation op, float f, int& e) const { return false; } virtual bool mayPredicate(const Instruction *, const Value *) const = 0; // whether @insn can be issued together with @next (order matters) virtual bool canDualIssue(const Instruction *insn, const Instruction *next) const { return false; } virtual int getLatency(const Instruction *) const { return 1; } virtual int getThroughput(const Instruction *) const { return 1; } virtual unsigned int getFileSize(DataFile) const = 0; virtual unsigned int getFileUnit(DataFile) const = 0; virtual uint32_t getSVAddress(DataFile, const Symbol *) const = 0; public: const bool hasJoin; // true if instructions have a join modifier const bool joinAnterior; // true if join is executed before the op const bool hasSWSched; // true if code should provide scheduling data static const uint8_t operationSrcNr[]; static const OpClass operationClass[]; static inline uint8_t getOpSrcNr(operation op) { return operationSrcNr[op]; } static inline OpClass getOpClass(operation op) { return operationClass[op]; } protected: uint32_t chipset; DataFile nativeFileMap[DATA_FILE_COUNT]; OpInfo opInfo[OP_LAST + 1]; }; const Target::OpInfo& Target::getOpInfo(const Instruction *insn) const { return opInfo[MIN2(insn->op, OP_LAST)]; } const Target::OpInfo& Target::getOpInfo(const operation op) const { return opInfo[op]; } inline DataFile Target::nativeFile(DataFile f) const { return nativeFileMap[f]; } } // namespace nv50_ir #endif // __NV50_IR_TARGET_H__