| //===-- 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. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// \file |
| /// \brief The SI code emitter produces machine code that can be executed |
| /// directly on the GPU device. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MCTargetDesc/AMDGPUMCTargetDesc.h" |
| #include "MCTargetDesc/AMDGPUMCCodeEmitter.h" |
| #include "llvm/MC/MCCodeEmitter.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCFixup.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" |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| /// \brief Helper type used in encoding |
| typedef union { |
| int32_t I; |
| float F; |
| } IntFloatUnion; |
| |
| class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { |
| SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; |
| void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; |
| const MCInstrInfo &MCII; |
| const MCRegisterInfo &MRI; |
| const MCSubtargetInfo &STI; |
| MCContext &Ctx; |
| |
| /// \brief Encode a sequence of registers with the correct alignment. |
| unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const; |
| |
| /// \brief Can this operand also contain immediate values? |
| bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const; |
| |
| /// \brief Encode an fp or int literal |
| uint32_t getLitEncoding(const MCOperand &MO) const; |
| |
| public: |
| SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, |
| const MCSubtargetInfo &sti, MCContext &ctx) |
| : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { } |
| |
| ~SIMCCodeEmitter() { } |
| |
| /// \breif Encode the instruction and write it to the OS. |
| virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, |
| SmallVectorImpl<MCFixup> &Fixups) const; |
| |
| /// \returns the encoding for an MCOperand. |
| virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, |
| SmallVectorImpl<MCFixup> &Fixups) const; |
| |
| /// \brief Encoding for when 2 consecutive registers are used |
| virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixup) const; |
| |
| /// \brief Encoding for when 4 consectuive registers are used |
| virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo, |
| SmallVectorImpl<MCFixup> &Fixup) const; |
| }; |
| |
| } // End anonymous namespace |
| |
| MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, |
| const MCRegisterInfo &MRI, |
| const MCSubtargetInfo &STI, |
| MCContext &Ctx) { |
| return new SIMCCodeEmitter(MCII, MRI, STI, Ctx); |
| } |
| |
| bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, |
| unsigned OpNo) const { |
| |
| unsigned RegClass = Desc.OpInfo[OpNo].RegClass; |
| return (AMDGPU::SSrc_32RegClassID == RegClass) || |
| (AMDGPU::SSrc_64RegClassID == RegClass) || |
| (AMDGPU::VSrc_32RegClassID == RegClass) || |
| (AMDGPU::VSrc_64RegClassID == RegClass); |
| } |
| |
| uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { |
| |
| IntFloatUnion Imm; |
| if (MO.isImm()) |
| Imm.I = MO.getImm(); |
| else if (MO.isFPImm()) |
| Imm.F = MO.getFPImm(); |
| else |
| return ~0; |
| |
| if (Imm.I >= 0 && Imm.I <= 64) |
| return 128 + Imm.I; |
| |
| if (Imm.I >= -16 && Imm.I <= -1) |
| return 192 + abs(Imm.I); |
| |
| if (Imm.F == 0.5f) |
| return 240; |
| |
| if (Imm.F == -0.5f) |
| return 241; |
| |
| if (Imm.F == 1.0f) |
| return 242; |
| |
| if (Imm.F == -1.0f) |
| return 243; |
| |
| if (Imm.F == 2.0f) |
| return 244; |
| |
| if (Imm.F == -2.0f) |
| return 245; |
| |
| if (Imm.F == 4.0f) |
| return 246; |
| |
| if (Imm.F == -4.0f) |
| return 247; |
| |
| return 255; |
| } |
| |
| void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, |
| SmallVectorImpl<MCFixup> &Fixups) const { |
| |
| uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); |
| const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); |
| unsigned bytes = Desc.getSize(); |
| |
| for (unsigned i = 0; i < bytes; i++) { |
| OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); |
| } |
| |
| if (bytes > 4) |
| return; |
| |
| // Check for additional literals in SRC0/1/2 (Op 1/2/3) |
| for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { |
| |
| // Check if this operand should be encoded as [SV]Src |
| if (!isSrcOperand(Desc, i)) |
| continue; |
| |
| // Is this operand a literal immediate? |
| const MCOperand &Op = MI.getOperand(i); |
| if (getLitEncoding(Op) != 255) |
| continue; |
| |
| // Yes! Encode it |
| IntFloatUnion Imm; |
| if (Op.isImm()) |
| Imm.I = Op.getImm(); |
| else |
| Imm.F = Op.getFPImm(); |
| |
| for (unsigned j = 0; j < 4; j++) { |
| OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); |
| } |
| |
| // Only one literal value allowed |
| break; |
| } |
| } |
| |
| uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, |
| const MCOperand &MO, |
| SmallVectorImpl<MCFixup> &Fixups) const { |
| if (MO.isReg()) |
| return MRI.getEncodingValue(MO.getReg()); |
| |
| if (MO.isExpr()) { |
| const MCExpr *Expr = MO.getExpr(); |
| MCFixupKind Kind = MCFixupKind(FK_PCRel_4); |
| Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); |
| return 0; |
| } |
| |
| // Figure out the operand number, needed for isSrcOperand check |
| unsigned OpNo = 0; |
| for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { |
| if (&MO == &MI.getOperand(OpNo)) |
| break; |
| } |
| |
| const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); |
| if (isSrcOperand(Desc, OpNo)) { |
| uint32_t Enc = getLitEncoding(MO); |
| if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) |
| return Enc; |
| |
| } else if (MO.isImm()) |
| return MO.getImm(); |
| |
| 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 = MRI.getEncodingValue(MI.getOperand(OpNo).getReg()); |
| return (regCode & 0xff) >> shift; |
| } |
| |
| 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); |
| } |