diff options
author | Tom Stellard <[email protected]> | 2012-08-17 19:42:11 +0000 |
---|---|---|
committer | Tom Stellard <[email protected]> | 2012-08-23 15:00:48 +0000 |
commit | 235318a578b3d7772a60590c7e76791ed6d1a78e (patch) | |
tree | 91891bdde0a4a16ed4ce49d711c86ec6ffc04233 /src/gallium/drivers/radeon/MCTargetDesc | |
parent | 2de24024c1ca5366e76f449b115392a97808ef2d (diff) |
radeon/llvm: Use the MCCodeEmitter for SI
Diffstat (limited to 'src/gallium/drivers/radeon/MCTargetDesc')
6 files changed, 478 insertions, 6 deletions
diff --git a/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUAsmBackend.cpp b/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUAsmBackend.cpp new file mode 100644 index 00000000000..10bf5a39366 --- /dev/null +++ b/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUAsmBackend.cpp @@ -0,0 +1,80 @@ +//===-- AMDGPUAsmBackend.cpp - AMDGPU Assembler Backend -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/AMDILMCTargetDesc.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +namespace { + +class AMDGPUMCObjectWriter : public MCObjectWriter { +public: + AMDGPUMCObjectWriter(raw_ostream &OS) : MCObjectWriter(OS, true) { } + virtual void ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + //XXX: Implement if necessary. + } + virtual void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) { + assert(!"Not implemented"); + } + + virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); + +}; + +class AMDGPUAsmBackend : public MCAsmBackend { +public: + AMDGPUAsmBackend(const Target &T) + : MCAsmBackend() {} + + virtual AMDGPUMCObjectWriter *createObjectWriter(raw_ostream &OS) const; + virtual unsigned getNumFixupKinds() const { return 0; }; + virtual void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const { assert(!"Not implemented"); } + virtual bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCInstFragment *DF, + const MCAsmLayout &Layout) const { + return false; + } + virtual void relaxInstruction(const MCInst &Inst, MCInst &Res) const { + assert(!"Not implemented"); + } + virtual bool mayNeedRelaxation(const MCInst &Inst) const { return false; } + virtual bool writeNopData(uint64_t Count, MCObjectWriter *OW) const { + return true; + } +}; + +} //End anonymous namespace + +void AMDGPUMCObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (MCAssembler::iterator I = Asm.begin(), E = Asm.end(); I != E; ++I) { + Asm.writeSectionData(I, Layout); + } +} + +MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T, StringRef TT) { + return new AMDGPUAsmBackend(T); +} + +AMDGPUMCObjectWriter * AMDGPUAsmBackend::createObjectWriter( + raw_ostream &OS) const { + return new AMDGPUMCObjectWriter(OS); +} diff --git a/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUMCCodeEmitter.h b/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUMCCodeEmitter.h new file mode 100644 index 00000000000..a75a8414e6c --- /dev/null +++ b/src/gallium/drivers/radeon/MCTargetDesc/AMDGPUMCCodeEmitter.h @@ -0,0 +1,59 @@ +//===-- AMDGPUCodeEmitter.h - AMDGPU Code Emitter interface -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// CodeEmitter interface for R600 and SI codegen. +// +//===----------------------------------------------------------------------===// + +#ifndef AMDGPUCODEEMITTER_H +#define AMDGPUCODEEMITTER_H + +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + + class MCInst; + class MCOperand; + + class AMDGPUMCCodeEmitter : public MCCodeEmitter { + public: + + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups) const; + + virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + return 0; + } + + virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + return 0; + } + virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + return 0; + } + virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const { + return Value; + } + virtual uint64_t i32LiteralEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + return 0; + } + virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + return 0; + } + }; + +} // End namespace llvm + +#endif // AMDGPUCODEEMITTER_H diff --git a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCAsmInfo.cpp b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCAsmInfo.cpp index 5b62311c6e6..1f3e4e7c0d4 100644 --- a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCAsmInfo.cpp +++ b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCAsmInfo.cpp @@ -19,6 +19,8 @@ using namespace llvm; AMDILMCAsmInfo::AMDILMCAsmInfo(const Target &T, StringRef &TT) : MCAsmInfo() { + HasSingleParameterDotFile = false; + WeakDefDirective = NULL; //===------------------------------------------------------------------===// HasSubsectionsViaSymbols = true; HasMachoZeroFillDirective = false; @@ -67,16 +69,10 @@ AMDILMCAsmInfo::AMDILMCAsmInfo(const Target &T, StringRef &TT) : MCAsmInfo() LCOMMDirectiveType = LCOMM::None; COMMDirectiveAlignmentIsInBytes = false; HasDotTypeDotSizeDirective = false; - HasSingleParameterDotFile = true; HasNoDeadStrip = true; HasSymbolResolver = false; WeakRefDirective = ".weakref\t"; - WeakDefDirective = ".weakdef\t"; LinkOnceDirective = NULL; - HiddenVisibilityAttr = MCSA_Hidden; - HiddenDeclarationVisibilityAttr = MCSA_Hidden; - ProtectedVisibilityAttr = MCSA_Protected; - //===--- Dwarf Emission Directives -----------------------------------===// HasLEB128 = true; SupportsDebugInformation = true; diff --git a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.cpp b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.cpp index 24cfb1f5355..6da38a67305 100644 --- a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.cpp +++ b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.cpp @@ -5,6 +5,7 @@ #include "llvm/MC/MCCodeGenInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" @@ -56,6 +57,15 @@ static MCInstPrinter *createAMDGPUMCInstPrinter(const Target &T, return new AMDGPUInstPrinter(MAI, MII, MRI); } +static MCStreamer *createMCStreamer(const Target &T, StringRef TT, + MCContext &Ctx, MCAsmBackend &MAB, + raw_ostream &_OS, + MCCodeEmitter *_Emitter, + bool RelaxAll, + bool NoExecStack) { + return createPureStreamer(Ctx, MAB, _OS, _Emitter); +} + extern "C" void LLVMInitializeAMDGPUTargetMC() { RegisterMCAsmInfo<AMDILMCAsmInfo> Y(TheAMDGPUTarget); @@ -69,4 +79,10 @@ extern "C" void LLVMInitializeAMDGPUTargetMC() { TargetRegistry::RegisterMCSubtargetInfo(TheAMDGPUTarget, createAMDGPUMCSubtargetInfo); TargetRegistry::RegisterMCInstPrinter(TheAMDGPUTarget, createAMDGPUMCInstPrinter); + + TargetRegistry::RegisterMCCodeEmitter(TheAMDGPUTarget, createAMDGPUMCCodeEmitter); + + TargetRegistry::RegisterMCAsmBackend(TheAMDGPUTarget, createAMDGPUAsmBackend); + + TargetRegistry::RegisterMCObjectStreamer(TheAMDGPUTarget, createMCStreamer); } diff --git a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.h b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.h index 2eab136e67a..d693ecc7069 100644 --- a/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.h +++ b/src/gallium/drivers/radeon/MCTargetDesc/AMDILMCTargetDesc.h @@ -15,12 +15,24 @@ #ifndef AMDILMCTARGETDESC_H #define AMDILMCTARGETDESC_H +#include "llvm/ADT/StringRef.h" + namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCRegisterInfo; class MCSubtargetInfo; class Target; extern Target TheAMDGPUTarget; +MCCodeEmitter *createAMDGPUMCCodeEmitter(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx); + +MCAsmBackend *createAMDGPUAsmBackend(const Target &T, StringRef TT); } // End llvm namespace #define GET_REGINFO_ENUM diff --git a/src/gallium/drivers/radeon/MCTargetDesc/SIMCCodeEmitter.cpp b/src/gallium/drivers/radeon/MCTargetDesc/SIMCCodeEmitter.cpp new file mode 100644 index 00000000000..1d7e84fdc5c --- /dev/null +++ b/src/gallium/drivers/radeon/MCTargetDesc/SIMCCodeEmitter.cpp @@ -0,0 +1,309 @@ +//===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The SI code emitter produces machine code that can be executed directly on +// the GPU device. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/AMDILMCTargetDesc.h" +#include "MCTargetDesc/AMDGPUMCCodeEmitter.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +#define LITERAL_REG 255 +#define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1)) +#define SI_INSTR_FLAGS_ENCODING_MASK 0xf + + +// These must be kept in sync with SIInstructions.td and also the +// InstrEncodingInfo array in SIInstrInfo.cpp. +// +// NOTE: This enum is only used to identify the encoding type within LLVM, +// the actual encoding type that is part of the instruction format is different +namespace SIInstrEncodingType { + enum Encoding { + EXP = 0, + LDS = 1, + MIMG = 2, + MTBUF = 3, + MUBUF = 4, + SMRD = 5, + SOP1 = 6, + SOP2 = 7, + SOPC = 8, + SOPK = 9, + SOPP = 10, + VINTRP = 11, + VOP1 = 12, + VOP2 = 13, + VOP3 = 14, + VOPC = 15 + }; +} + +using namespace llvm; + +namespace { +class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { + SIMCCodeEmitter(const SIMCCodeEmitter &); // DO NOT IMPLEMENT + void operator=(const SIMCCodeEmitter &); // DO NOT IMPLEMENT + const MCInstrInfo &MCII; + const MCSubtargetInfo &STI; + MCContext &Ctx; + +public: + SIMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, + MCContext &ctx) + : MCII(mcii), STI(sti), Ctx(ctx) { } + + ~SIMCCodeEmitter() { } + + /// getBinaryCodeForInstr - Function generated by tablegen for encoding + /// instructions based on the *.td files. +// virtual uint64_t getBinaryCodeForInstr(const MCInst &MI, +// SmallVectorImpl<MCFixup> &Fixups) const; + + /// EncodeInstruction - Encode the instruction and write it to the OS. + virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; + + /// getMachineOpValue - Reutrn the encoding for an MCOperand. + virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const; + +public: + + /// GPRAlign - Encode a sequence of registers with the correct alignment. + unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const; + + /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used + virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const; + + /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used + virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const; + + /// i32LiteralEncode - Encode an i32 literal this is used as an operand + /// for an instruction in place of a register. + virtual uint64_t i32LiteralEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const; + + /// SMRDmemriEncode - Encoding for SMRD indexed loads + virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const; + + /// VOPPostEncode - Post-Encoder method for VOP instructions + virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const; + +private: + + ///getEncodingType = Return this SIInstrEncodingType for this instruction. + unsigned getEncodingType(const MCInst &MI) const; + + ///getEncodingBytes - Get then size in bytes of this instructions encoding. + unsigned getEncodingBytes(const MCInst &MI) const; + + /// getRegBinaryCode - Returns the hardware encoding for a register + unsigned getRegBinaryCode(unsigned reg) const; + + /// getHWRegNum - Generated function that returns the hardware encoding for + /// a register + unsigned getHWRegNum(unsigned reg) const; + +}; + +} // End anonymous namespace + +MCCodeEmitter *llvm::createAMDGPUMCCodeEmitter(const MCInstrInfo &MCII, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + if (STI.getFeatureBits() & AMDGPU::Feature64BitPtr) { + return new SIMCCodeEmitter(MCII, STI, Ctx); + } else { + return NULL; + } +} + +void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const { + uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); + unsigned bytes = getEncodingBytes(MI); + for (unsigned i = 0; i < bytes; i++) { + OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); + } +} + +uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, + const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + if (MO.isReg()) { + return getRegBinaryCode(MO.getReg()); + } else if (MO.isImm()) { + return MO.getImm(); + } else if (MO.isFPImm()) { + // XXX: Not all instructions can use inline literals + // XXX: We should make sure this is a 32-bit constant + return LITERAL_REG; + } else{ + llvm_unreachable("Encoding of this operand type is not supported yet."); + } + return 0; +} + +//===----------------------------------------------------------------------===// +// Custom Operand Encodings +//===----------------------------------------------------------------------===// + +unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo, + unsigned shift) const { + unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg()); + return regCode >> shift; + return 0; +} +unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI, + unsigned OpNo , + SmallVectorImpl<MCFixup> &Fixup) const { + return GPRAlign(MI, OpNo, 1); +} + +unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI, + unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const { + return GPRAlign(MI, OpNo, 2); +} + +uint64_t SIMCCodeEmitter::i32LiteralEncode(const MCInst &MI, + unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const { + return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32); +} + +#define SMRD_OFFSET_MASK 0xff +#define SMRD_IMM_SHIFT 8 +#define SMRD_SBASE_MASK 0x3f +#define SMRD_SBASE_SHIFT 9 +/// SMRDmemriEncode - This function is responsibe for encoding the offset +/// and the base ptr for SMRD instructions it should return a bit string in +/// this format: +/// +/// OFFSET = bits{7-0} +/// IMM = bits{8} +/// SBASE = bits{14-9} +/// +uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixup) const { + uint32_t Encoding; + + const MCOperand &OffsetOp = MI.getOperand(OpNo + 1); + + //XXX: Use this function for SMRD loads with register offsets + assert(OffsetOp.isImm()); + + Encoding = + (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK) + | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit + | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT) + ; + + return Encoding; +} + +//===----------------------------------------------------------------------===// +// Post Encoder Callbacks +//===----------------------------------------------------------------------===// + +uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{ + unsigned encodingType = getEncodingType(MI); + unsigned numSrcOps; + unsigned vgprBitOffset; + + if (encodingType == SIInstrEncodingType::VOP3) { + numSrcOps = 3; + vgprBitOffset = 32; + } else { + numSrcOps = 1; + vgprBitOffset = 0; + } + + // Add one to skip over the destination reg operand. + for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) { + const MCOperand &MO = MI.getOperand(opIdx); + if (MO.isReg()) { + unsigned reg = MI.getOperand(opIdx).getReg(); + if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) || + AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) { + Value |= (VGPR_BIT(opIdx)) << vgprBitOffset; + } + } else if (MO.isFPImm()) { + // XXX: Not all instructions can use inline literals + // XXX: We should make sure this is a 32-bit constant + Value |= ((uint64_t)MO.getFPImm()) << 32; + } + } + return Value; +} + +//===----------------------------------------------------------------------===// +// Encoding helper functions +//===----------------------------------------------------------------------===// + +unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const { + return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK; +} + +unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const { + + // Instructions with literal constants are expanded to 64-bits, and + // the constant is stored in bits [63:32] + for (unsigned i = 0; i < MI.getNumOperands(); i++) { + if (MI.getOperand(i).isFPImm()) { + return 8; + } + } + + // This instruction always has a literal + if (MI.getOpcode() == AMDGPU::S_MOV_IMM_I32) { + return 8; + } + + unsigned encoding_type = getEncodingType(MI); + switch (encoding_type) { + case SIInstrEncodingType::EXP: + case SIInstrEncodingType::LDS: + case SIInstrEncodingType::MUBUF: + case SIInstrEncodingType::MTBUF: + case SIInstrEncodingType::MIMG: + case SIInstrEncodingType::VOP3: + return 8; + default: + return 4; + } +} + + +unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const { + switch (reg) { + case AMDGPU::M0: return 124; + case AMDGPU::SREG_LIT_0: return 128; + default: return getHWRegNum(reg); + } +} + +#define SIRegisterInfo SIMCCodeEmitter +#include "SIRegisterGetHWRegNum.inc" +#undef SIRegisterInfo + +#include "AMDGPUGenMCCodeEmitter.inc" |