//
//===----------------------------------------------------------------------===//
-#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
+#include "AMDGPU.h"
+#include "MCTargetDesc/AMDGPUFixupKinds.h"
#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
+#include "SIDefines.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/MC/MCFixup.h"
#include "llvm/Support/raw_ostream.h"
-#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
+ SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
+ void operator=(const SIMCCodeEmitter &) = delete;
const MCInstrInfo &MCII;
const MCRegisterInfo &MRI;
- const MCSubtargetInfo &STI;
MCContext &Ctx;
+ /// \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, unsigned OpSize) const;
+
public:
SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
- const MCSubtargetInfo &sti, MCContext &ctx)
- : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { }
+ MCContext &ctx)
+ : MCII(mcii), MRI(mri), 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;
+ /// \brief Encode the instruction and write it to the OS.
+ void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
/// \returns the encoding for an MCOperand.
- virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
- SmallVectorImpl<MCFixup> &Fixups) const;
+ uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+
+ /// \brief Use a fixup to encode the simm16 field for SOPP branch
+ /// instructions.
+ unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+};
-public:
+} // End anonymous namespace
- /// \brief Encode a sequence of registers with the correct alignment.
- unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
+MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new SIMCCodeEmitter(MCII, MRI, Ctx);
+}
- /// \brief Encoding for when 2 consecutive registers are used
- virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo,
- SmallVectorImpl<MCFixup> &Fixup) const;
+bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
+ unsigned OpNo) const {
+ unsigned OpType = Desc.OpInfo[OpNo].OperandType;
- /// \brief Encoding for when 4 consectuive registers are used
- virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo,
- SmallVectorImpl<MCFixup> &Fixup) const;
+ return OpType == AMDGPU::OPERAND_REG_IMM32 ||
+ OpType == AMDGPU::OPERAND_REG_INLINE_C;
+}
- /// \brief Encoding for SMRD indexed loads
- virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
- SmallVectorImpl<MCFixup> &Fixup) const;
+// Returns the encoding value to use if the given integer is an integer inline
+// immediate value, or 0 if it is not.
+template <typename IntTy>
+static uint32_t getIntInlineImmEncoding(IntTy Imm) {
+ if (Imm >= 0 && Imm <= 64)
+ return 128 + Imm;
- /// \brief Post-Encoder method for VOP instructions
- virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const;
+ if (Imm >= -16 && Imm <= -1)
+ return 192 + std::abs(Imm);
-private:
+ return 0;
+}
- /// \returns this SIInstrEncodingType for this instruction.
- unsigned getEncodingType(const MCInst &MI) const;
+static uint32_t getLit32Encoding(uint32_t Val) {
+ uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
+ if (IntImm != 0)
+ return IntImm;
- /// \brief Get then size in bytes of this instructions encoding.
- unsigned getEncodingBytes(const MCInst &MI) const;
+ if (Val == FloatToBits(0.5f))
+ return 240;
- /// \returns the hardware encoding for a register
- unsigned getRegBinaryCode(unsigned reg) const;
+ if (Val == FloatToBits(-0.5f))
+ return 241;
- /// \brief Generated function that returns the hardware encoding for
- /// a register
- unsigned getHWRegNum(unsigned reg) const;
+ if (Val == FloatToBits(1.0f))
+ return 242;
-};
+ if (Val == FloatToBits(-1.0f))
+ return 243;
-} // End anonymous namespace
+ if (Val == FloatToBits(2.0f))
+ return 244;
-MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
- const MCRegisterInfo &MRI,
- const MCSubtargetInfo &STI,
- MCContext &Ctx) {
- return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
+ if (Val == FloatToBits(-2.0f))
+ return 245;
+
+ if (Val == FloatToBits(4.0f))
+ return 246;
+
+ if (Val == FloatToBits(-4.0f))
+ return 247;
+
+ return 255;
+}
+
+static uint32_t getLit64Encoding(uint64_t Val) {
+ uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
+ if (IntImm != 0)
+ return IntImm;
+
+ if (Val == DoubleToBits(0.5))
+ return 240;
+
+ if (Val == DoubleToBits(-0.5))
+ return 241;
+
+ if (Val == DoubleToBits(1.0))
+ return 242;
+
+ if (Val == DoubleToBits(-1.0))
+ return 243;
+
+ if (Val == DoubleToBits(2.0))
+ return 244;
+
+ if (Val == DoubleToBits(-2.0))
+ return 245;
+
+ if (Val == DoubleToBits(4.0))
+ return 246;
+
+ if (Val == DoubleToBits(-4.0))
+ return 247;
+
+ return 255;
+}
+
+uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
+ unsigned OpSize) const {
+ if (MO.isExpr())
+ return 255;
+
+ assert(!MO.isFPImm());
+
+ if (!MO.isImm())
+ return ~0;
+
+ if (OpSize == 4)
+ return getLit32Encoding(static_cast<uint32_t>(MO.getImm()));
+
+ assert(OpSize == 8);
+
+ return getLit64Encoding(static_cast<uint64_t>(MO.getImm()));
}
void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
- SmallVectorImpl<MCFixup> &Fixups) const {
- uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
- unsigned bytes = getEncodingBytes(MI);
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
+ 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));
}
-}
-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
- union {
- float F;
- uint32_t I;
- } Imm;
- Imm.F = MO.getFPImm();
- return Imm.I;
- } else 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;
- } else{
- llvm_unreachable("Encoding of this operand type is not supported yet.");
- }
- return 0;
-}
+ if (bytes > 4)
+ return;
-//===----------------------------------------------------------------------===//
-// Custom Operand Encodings
-//===----------------------------------------------------------------------===//
+ // Check for additional literals in SRC0/1/2 (Op 1/2/3)
+ for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
-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);
-}
+ // Check if this operand should be encoded as [SV]Src
+ if (!isSrcOperand(Desc, i))
+ continue;
-unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI,
- unsigned OpNo,
- SmallVectorImpl<MCFixup> &Fixup) const {
- return GPRAlign(MI, OpNo, 2);
-}
+ int RCID = Desc.OpInfo[i].RegClass;
+ const MCRegisterClass &RC = MRI.getRegClass(RCID);
-#define SMRD_OFFSET_MASK 0xff
-#define SMRD_IMM_SHIFT 8
-#define SMRD_SBASE_MASK 0x3f
-#define SMRD_SBASE_SHIFT 9
-/// 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;
-}
+ // Is this operand a literal immediate?
+ const MCOperand &Op = MI.getOperand(i);
+ if (getLitEncoding(Op, RC.getSize()) != 255)
+ continue;
-//===----------------------------------------------------------------------===//
-// Post Encoder Callbacks
-//===----------------------------------------------------------------------===//
+ // Yes! Encode it
+ int64_t Imm = 0;
-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;
- }
+ if (Op.isImm())
+ Imm = Op.getImm();
+ else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
+ llvm_unreachable("Must be immediate or expr");
- // 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()) {
- union {
- float f;
- uint32_t i;
- } Imm;
- // XXX: Not all instructions can use inline literals
- // XXX: We should make sure this is a 32-bit constant
- Imm.f = MO.getFPImm();
- Value |= ((uint64_t)Imm.i) << 32;
+ for (unsigned j = 0; j < 4; j++) {
+ OS.write((uint8_t) ((Imm >> (8 * j)) & 0xff));
}
+
+ // Only one literal value allowed
+ break;
}
- return Value;
}
-//===----------------------------------------------------------------------===//
-// Encoding helper functions
-//===----------------------------------------------------------------------===//
+unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
-unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const {
- return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK;
-}
+ if (MO.isExpr()) {
+ const MCExpr *Expr = MO.getExpr();
+ MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
+ Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
+ return 0;
+ }
-unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const {
+ return getMachineOpValue(MI, MO, Fixups, STI);
+}
- // These instructions aren't real instructions with an encoding type, so
- // we need to manually specify their size.
- switch (MI.getOpcode()) {
- default: break;
- case AMDGPU::SI_LOAD_LITERAL_I32:
- case AMDGPU::SI_LOAD_LITERAL_F32:
- return 4;
+uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
+ const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ if (MO.isReg())
+ return MRI.getEncodingValue(MO.getReg());
+
+ if (MO.isExpr()) {
+ const MCSymbolRefExpr *Expr = cast<MCSymbolRefExpr>(MO.getExpr());
+ MCFixupKind Kind;
+ const MCSymbol *Sym =
+ Ctx.GetOrCreateSymbol(StringRef(END_OF_TEXT_LABEL_NAME));
+
+ if (&Expr->getSymbol() == Sym) {
+ // Add the offset to the beginning of the constant values.
+ Kind = (MCFixupKind)AMDGPU::fixup_si_end_of_text;
+ } else {
+ // This is used for constant data stored in .rodata.
+ Kind = (MCFixupKind)AMDGPU::fixup_si_rodata;
+ }
+ Fixups.push_back(MCFixup::Create(4, Expr, Kind, MI.getLoc()));
}
- 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;
+ // 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)) {
+ int RCID = Desc.OpInfo[OpNo].RegClass;
+ const MCRegisterClass &RC = MRI.getRegClass(RCID);
-unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const {
- switch (reg) {
- case AMDGPU::M0: return 124;
- case AMDGPU::SREG_LIT_0: return 128;
- case AMDGPU::SI_LITERAL_CONSTANT: return 255;
- default: return MRI.getEncodingValue(reg);
- }
+ uint32_t Enc = getLitEncoding(MO, RC.getSize());
+ 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;
}