713 changes: 384 additions & 329 deletions llvm/lib/Target/M68k/M68kInstrArithmetic.td

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions llvm/lib/Target/M68k/M68kInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ class MxEncEA<MxBead reg, MxBead mode, MxBead da = MxBeadIgnore> {
MxBead DA = da;
}

class MxEncMemOp {
dag EA = (ascend);
dag Supplement = (ascend);
}

// FIXME: Is there a way to factorize the addressing mode suffix (i.e.
// 'r', 'd', 'a' etc.) and use something like multiclass to replace?
def MxEncEAr_0: MxEncEA<MxBeadDAReg<0>, MxBead2Bits<0b00>>;
Expand Down Expand Up @@ -237,6 +242,93 @@ def MxEncEAq : MxEncEA<MxBead3Bits<0b010>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
def MxEncEAk : MxEncEA<MxBead3Bits<0b011>, MxBead2Bits<0b11>, MxBead1Bit<1>>;
def MxEncEAi : MxEncEA<MxBead3Bits<0b100>, MxBead2Bits<0b11>, MxBead1Bit<1>>;

class MxEncBriefExt<string reg_opnd, string disp_opnd,
bit size_w_l = false, int scale = 1> {
dag Value = (descend
// D/A + REGISTER
(operand "$"#reg_opnd, 4),
// W/L
size_w_l,
// SCALE
!cond(
!eq(scale, 1) : 0b00,
!eq(scale, 2) : 0b01,
!eq(scale, 4) : 0b10,
!eq(scale, 8) : 0b11
),
0b0,
// Displacement
(operand "$"#disp_opnd, 8)
);
}

class MxEncAddrMode_k<string opnd_name> : MxEncMemOp {
let EA = (descend /*MODE*/0b111,
/*REGISTER*/0b011);

let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
/*W/L*/true>.Value;
}

class MxEncAddrMode_q<string opnd_name> : MxEncMemOp {
let EA = (descend /*MODE*/0b111,
/*REGISTER*/0b010);

// 16-bit Displacement
let Supplement = (operand "$"#opnd_name, 16);
}

class MxEncAddrMode_p<string opnd_name> : MxEncMemOp {
let EA = (descend /*MODE*/0b101,
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));

// 16-bit Displacement
let Supplement = (operand "$"#opnd_name#".disp", 16);
}

class MxEncAddrMode_f<string opnd_name> : MxEncMemOp {
let EA = (descend /*MODE*/0b110,
/*REGISTER*/(operand "$"#opnd_name#".reg", 3));

let Supplement = MxEncBriefExt<opnd_name#".index", opnd_name#".disp",
/*W/L*/true>.Value;
}

class MxEncAddrMode_j<string reg_opnd> : MxEncMemOp {
let EA = (descend /*MODE*/0b010,
/*REGISTER*/(operand "$"#reg_opnd, 3));
}

class MxEncAddrMode_i<string opnd_name, int size> : MxEncMemOp {
let EA = (descend /*MODE*/0b111,
/*REGISTER*/0b100);

// Immediate
let Supplement =
!cond(
!eq(size, 8) : (descend 0b00000000, (operand "$"#opnd_name, 8)),
!eq(size, 16) : (operand "$"#opnd_name, 16),
!eq(size, 32) : (ascend (slice "$"#opnd_name, 31, 16),
(slice "$"#opnd_name, 15, 0))
);
}

// abs.W -> size_w_l = false
// abs.L -> size_w_l = true
class MxEncAddrMode_abs<string opnd_name, bit size_w_l = false> : MxEncMemOp {
let EA = (descend /*MODE*/0b111,
/*REGISTER*/0b00, size_w_l);

// Absolute address
let Supplement = !if(size_w_l,
// abs.L
(ascend (slice "$"#opnd_name, 31, 16),
(slice "$"#opnd_name, 15, 0)),
// abs.W
(operand "$"#opnd_name, 16)
);
}

// Allows you to specify each bit of opcode
class MxEncOpMode<MxBead b0, MxBead b1 = MxBeadIgnore, MxBead b2 = MxBeadIgnore> {
MxBead B0 = b0;
Expand Down Expand Up @@ -332,6 +424,16 @@ def MxEncSize16 : MxEncSize<0b01>;
def MxEncSize32 : MxEncSize<0b10>;
def MxEncSize64 : MxEncSize<0b11>;

// TODO: Remove "New" in the name after the codebead-based
// representation is deprecated.
class MxNewEncSize<bits<2> value> {
bits<2> Value = value;
}
def MxNewEncSize8 : MxNewEncSize<0b00>;
def MxNewEncSize16 : MxNewEncSize<0b01>;
def MxNewEncSize32 : MxNewEncSize<0b10>;
def MxNewEncSize64 : MxNewEncSize<0b11>;

// M68k INSTRUCTION. Most instructions specify the location of an operand by
// using the effective address field in the operation word. The effective address
// is composed of two 3-bit fields: the mode field and the register field. The
Expand All @@ -357,6 +459,7 @@ class MxInst<dag outs, dag ins,

// Byte stream
field bits<192> Beads = beads.Value;
dag Inst = (ascend);

// Number of bytes
let Size = 0;
Expand Down
38 changes: 22 additions & 16 deletions llvm/lib/Target/M68k/M68kInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,13 @@ def MxARIPD32_TC : MxMemOp<(ops AR32_TC), MxSize32, "e", "printARIPD32Mem", MxA
// extension word. The reference is classified as a data reference with the
// exception of the jump and jump-to-subroutine instructions.
def MxARID : MxOpClass<"ARID">;
def MxARID8 : MxMemOp<(ops i16imm, AR32), MxSize8, "p", "printARID8Mem", MxARID>;
def MxARID16 : MxMemOp<(ops i16imm, AR32), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32 : MxMemOp<(ops i16imm, AR32), MxSize32, "p", "printARID32Mem", MxARID>;
def MxARID8 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize8, "p", "printARID8Mem", MxARID>;
def MxARID16 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize32, "p", "printARID32Mem", MxARID>;

def MxARID8_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize8, "p", "printARID8Mem", MxARID>;
def MxARID16_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize32, "p", "printARID32Mem", MxARID>;
def MxARID8_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize8, "p", "printARID8Mem", MxARID>;
def MxARID16_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize16, "p", "printARID16Mem", MxARID>;
def MxARID32_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize32, "p", "printARID32Mem", MxARID>;

// ADDRESS REGISTER INDIRECT WITH INDEX. This addressing mode requires one word
// of extension. The address of the operand is the sum of the address in the
Expand All @@ -306,13 +306,19 @@ def MxARID32_TC : MxMemOp<(ops i16imm, AR32_TC), MxSize32, "p", "printARID32Me
// The reference is classified as a data reference with the exception of the
// jump and jump-to-subroutine instructions
def MxARII : MxOpClass<"ARII">;
def MxARII8 : MxMemOp<(ops i8imm, AR32, XR32), MxSize8, "f", "printARII8Mem", MxARII>;
def MxARII16 : MxMemOp<(ops i8imm, AR32, XR32), MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32 : MxMemOp<(ops i8imm, AR32, XR32), MxSize32, "f", "printARII32Mem", MxARII>;

def MxARII8_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize8, "f", "printARII8Mem", MxARII>;
def MxARII16_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32_TC : MxMemOp<(ops i8imm, AR32_TC, XR32_TC), MxSize32, "f", "printARII32Mem", MxARII>;
def MxARII8 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
MxSize8, "f", "printARII8Mem", MxARII>;
def MxARII16 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index),
MxSize32, "f", "printARII32Mem", MxARII>;

def MxARII8_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
MxSize8, "f", "printARII8Mem", MxARII>;
def MxARII16_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
MxSize16, "f", "printARII16Mem", MxARII>;
def MxARII32_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index),
MxSize32, "f", "printARII32Mem", MxARII>;

// ABSOLUTE SHORT ADDRESS. This addressing mode requires one word of extension.
// The address of the operand is the extension word. The 16-bit address is sign
Expand Down Expand Up @@ -360,9 +366,9 @@ def MxPCD32 : MxMemOp<(ops i16imm), MxSize32, "q", "printPCD32Mem", MxPCD>;
// word, and the contents of the index register. The value in the program
// counter is the address of the extension word. This reference is classified as
// a program reference.
def MxPCI8 : MxMemOp<(ops i8imm, XR32), MxSize8, "k", "printPCI8Mem", MxPCI>;
def MxPCI16 : MxMemOp<(ops i8imm, XR32), MxSize16, "k", "printPCI16Mem", MxPCI>;
def MxPCI32 : MxMemOp<(ops i8imm, XR32), MxSize32, "k", "printPCI32Mem", MxPCI>;
def MxPCI8 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize8, "k", "printPCI8Mem", MxPCI>;
def MxPCI16 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize16, "k", "printPCI16Mem", MxPCI>;
def MxPCI32 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize32, "k", "printPCI32Mem", MxPCI>;
} // OPERAND_PCREL

def MxImm : AsmOperandClass {
Expand Down
50 changes: 50 additions & 0 deletions llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ class M68kMCCodeEmitter : public MCCodeEmitter {
const MCInstrInfo &MCII;
MCContext &Ctx;

void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
APInt &Inst, APInt &Scratch,
const MCSubtargetInfo &STI) const;

void getMachineOpValue(const MCInst &MI, const MCOperand &Op, APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;

public:
M68kMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {}
Expand Down Expand Up @@ -72,6 +80,28 @@ class M68kMCCodeEmitter : public MCCodeEmitter {

} // end anonymous namespace

#include "M68kGenMCCodeEmitter.inc"

void M68kMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &Op,
APInt &Value,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
// Register
if (Op.isReg()) {
unsigned RegNum = Op.getReg();
const auto *RI = Ctx.getRegisterInfo();
Value |= RI->getEncodingValue(RegNum);
// Setup the D/A bit
if (M68kII::isAddressRegister(RegNum))
Value |= 0b1000;
} else if (Op.isImm()) {
// Immediate
Value |= static_cast<uint64_t>(Op.getImm());
} else {
llvm_unreachable("Unsupported operand type");
}
}

unsigned M68kMCCodeEmitter::encodeBits(unsigned ThisByte, uint8_t Bead,
const MCInst &MI,
const MCInstrDesc &Desc,
Expand Down Expand Up @@ -321,6 +351,26 @@ void M68kMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "("
<< Opcode << ")\n");

// Try using the new method first.
APInt EncodedInst(16, 0U);
APInt Scratch(16, 0U);
getBinaryCodeForInstr(MI, Fixups, EncodedInst, Scratch, STI);
if (EncodedInst.getBitWidth()) {
LLVM_DEBUG(dbgs() << "Instruction " << MCII.getName(Opcode) << "(" << Opcode
<< ") is using the new code emitter\n");
ArrayRef<uint64_t> Data(EncodedInst.getRawData(),
EncodedInst.getNumWords());
int64_t InstSize = EncodedInst.getBitWidth();
for (uint64_t Word : Data) {
for (int i = 0; i < 4 && InstSize > 0; ++i, InstSize -= 16) {
support::endian::write<uint16_t>(OS, static_cast<uint16_t>(Word),
support::big);
Word >>= 16;
}
}
return;
}

const uint8_t *Beads = getGenInstrBeads(MI);
if (!Beads || !*Beads) {
llvm_unreachable("*** Instruction does not have Beads defined");
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/M68k/Control/cmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ define void @test20(i32 %bf.load, i8 %x1, i8* %b_addr) {
; CHECK-NEXT: move.l (16,%sp), %a0
; CHECK-NEXT: move.b (15,%sp), %d2
; CHECK-NEXT: and.l #255, %d2
; CHECK-NEXT: add.l %d2, %d1
; CHECK-NEXT: add.l %d1, %d2
; CHECK-NEXT: sne (%a0)
; CHECK-NEXT: cmpi.l #0, %d0
; CHECK-NEXT: lea (d,%pc), %a0
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/MC/Disassembler/M68k/arithmetic.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s
# Disable this particular test until migration to the new code emitter is
# finished.
# XFAIL: *

# CHECK: adda.l %a0, %a1
0xd3 0xc8
Expand Down
93 changes: 93 additions & 0 deletions llvm/test/TableGen/VarLenEncoder.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// RUN: llvm-tblgen -gen-emitter -I %p/../../include %s | FileCheck %s

// Check if VarLenCodeEmitterGen works correctly.

include "llvm/Target/Target.td"

def ArchInstrInfo : InstrInfo { }

def Arch : Target {
let InstructionSet = ArchInstrInfo;
}

def Reg : Register<"reg">;

def RegClass : RegisterClass<"foo", [i64], 0, (add Reg)>;

def GR64 : RegisterOperand<RegClass>;

class MyMemOperand<dag sub_ops> : Operand<iPTR> {
let MIOperandInfo = sub_ops;
dag Base;
dag Extension;
}

class MyVarInst<MyMemOperand memory_op> : Instruction {
dag Inst;

let OutOperandList = (outs GR64:$dst);
let InOperandList = (ins memory_op:$src);

// Testing `ascend` and `descend`
let Inst = (ascend
(descend 0b10110111, memory_op.Base),
memory_op.Extension,
// Testing operand referencing.
(operand "$dst", 4),
// Testing operand referencing with a certain bit range.
(slice "$dst", 3, 1)
);
}

class MemOp16<string op_name> : MyMemOperand<(ops GR64:$reg, i16imm:$offset)> {
// Testing sub-operand referencing.
let Base = (operand "$"#op_name#".reg", 8);
let Extension = (operand "$"#op_name#".offset", 16);
}

class MemOp32<string op_name> : MyMemOperand<(ops GR64:$reg, i32imm:$offset)> {
let Base = (operand "$"#op_name#".reg", 8);
// Testing variable-length instruction encoding.
let Extension = (operand "$"#op_name#".offset", 32);
}

def FOO16 : MyVarInst<MemOp16<"src">>;
def FOO32 : MyVarInst<MemOp32<"src">>;

// The fixed bits part
// CHECK: {/*NumBits*/39,
// CHECK-SAME: // FOO16
// CHECK: {/*NumBits*/55,
// CHECK-SAME: // FOO32
// CHECK: UINT64_C(46848), // FOO16
// CHECK: UINT64_C(46848), // FOO32

// CHECK-LABEL: case ::FOO16: {
// CHECK: Scratch = Scratch.zextOrSelf(39);
// src.reg
// CHECK: getMachineOpValue(MI, MI.getOperand(1), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0);
// src.offset
// CHECK: getMachineOpValue(MI, MI.getOperand(2), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(16, 0), 16);
// 1st dst
// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 32);
// 2nd dst
// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 36);

// CHECK-LABEL: case ::FOO32: {
// CHECK: Scratch = Scratch.zextOrSelf(55);
// src.reg
// CHECK: getMachineOpValue(MI, MI.getOperand(1), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(8, 0), 0);
// src.offset
// CHECK: getMachineOpValue(MI, MI.getOperand(2), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(32, 0), 16);
// 1st dst
// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(4, 0), 48);
// 2nd dst
// CHECK: getMachineOpValue(MI, MI.getOperand(0), Scratch, Fixups, STI);
// CHECK: Inst.insertBits(Scratch.extractBits(3, 1), 52);
1 change: 1 addition & 0 deletions llvm/utils/TableGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_tablegen(llvm-tblgen LLVM
SubtargetFeatureInfo.cpp
TableGen.cpp
Types.cpp
VarLenCodeEmitterGen.cpp
X86DisassemblerTables.cpp
X86EVEX2VEXTablesEmitter.cpp
X86FoldTablesEmitter.cpp
Expand Down
233 changes: 121 additions & 112 deletions llvm/utils/TableGen/CodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "CodeGenTarget.h"
#include "SubtargetFeatureInfo.h"
#include "Types.h"
#include "VarLenCodeEmitterGen.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
Expand Down Expand Up @@ -396,132 +397,140 @@ void CodeEmitterGen::run(raw_ostream &o) {
ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();

const CodeGenHwModes &HWM = Target.getHwModes();
// The set of HwModes used by instruction encodings.
std::set<unsigned> HwModes;
BitWidth = 0;
for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo"))
continue;
if (any_of(NumberedInstructions, [](const CodeGenInstruction *CGI) {
Record *R = CGI->TheDef;
return R->getValue("Inst") && isa<DagInit>(R->getValueInit("Inst"));
})) {
emitVarLenCodeEmitter(Records, o);
} else {
const CodeGenHwModes &HWM = Target.getHwModes();
// The set of HwModes used by instruction encodings.
std::set<unsigned> HwModes;
BitWidth = 0;
for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo"))
continue;

if (const RecordVal *RV = R->getValue("EncodingInfos")) {
if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
for (auto &KV : EBM) {
BitsInit *BI = KV.second->getValueAsBitsInit("Inst");
BitWidth = std::max(BitWidth, BI->getNumBits());
HwModes.insert(KV.first);
if (const RecordVal *RV = R->getValue("EncodingInfos")) {
if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
EncodingInfoByHwMode EBM(DI->getDef(), HWM);
for (auto &KV : EBM) {
BitsInit *BI = KV.second->getValueAsBitsInit("Inst");
BitWidth = std::max(BitWidth, BI->getNumBits());
HwModes.insert(KV.first);
}
continue;
}
continue;
}
BitsInit *BI = R->getValueAsBitsInit("Inst");
BitWidth = std::max(BitWidth, BI->getNumBits());
}
BitsInit *BI = R->getValueAsBitsInit("Inst");
BitWidth = std::max(BitWidth, BI->getNumBits());
}
UseAPInt = BitWidth > 64;

// Emit function declaration
if (UseAPInt) {
o << "void " << Target.getName()
<< "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
<< " SmallVectorImpl<MCFixup> &Fixups,\n"
<< " APInt &Inst,\n"
<< " APInt &Scratch,\n"
<< " const MCSubtargetInfo &STI) const {\n";
} else {
o << "uint64_t " << Target.getName();
o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
<< " SmallVectorImpl<MCFixup> &Fixups,\n"
<< " const MCSubtargetInfo &STI) const {\n";
}

// Emit instruction base values
if (HwModes.empty()) {
emitInstructionBaseValues(o, NumberedInstructions, Target, -1);
} else {
for (unsigned HwMode : HwModes)
emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode);
}
UseAPInt = BitWidth > 64;

if (!HwModes.empty()) {
o << " const uint64_t *InstBits;\n";
o << " unsigned HwMode = STI.getHwMode();\n";
o << " switch (HwMode) {\n";
o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n";
for (unsigned I : HwModes) {
o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name
<< "; break;\n";
// Emit function declaration
if (UseAPInt) {
o << "void " << Target.getName()
<< "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
<< " SmallVectorImpl<MCFixup> &Fixups,\n"
<< " APInt &Inst,\n"
<< " APInt &Scratch,\n"
<< " const MCSubtargetInfo &STI) const {\n";
} else {
o << "uint64_t " << Target.getName();
o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
<< " SmallVectorImpl<MCFixup> &Fixups,\n"
<< " const MCSubtargetInfo &STI) const {\n";
}
o << " };\n";
}

// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;
// Emit instruction base values
if (HwModes.empty()) {
emitInstructionBaseValues(o, NumberedInstructions, Target, -1);
} else {
for (unsigned HwMode : HwModes)
emitInstructionBaseValues(o, NumberedInstructions, Target, (int)HwMode);
}

// Construct all cases statement for each opcode
for (Record *R : Insts) {
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo"))
continue;
std::string InstName =
(R->getValueAsString("Namespace") + "::" + R->getName()).str();
std::string Case = getInstructionCase(R, Target);
if (!HwModes.empty()) {
o << " const uint64_t *InstBits;\n";
o << " unsigned HwMode = STI.getHwMode();\n";
o << " switch (HwMode) {\n";
o << " default: llvm_unreachable(\"Unknown hardware mode!\"); break;\n";
for (unsigned I : HwModes) {
o << " case " << I << ": InstBits = InstBits_" << HWM.getMode(I).Name
<< "; break;\n";
}
o << " };\n";
}

CaseMap[Case].push_back(std::move(InstName));
}
// Map to accumulate all the cases.
std::map<std::string, std::vector<std::string>> CaseMap;

// Emit initial function code
if (UseAPInt) {
int NumWords = APInt::getNumWords(BitWidth);
int NumBytes = (BitWidth + 7) / 8;
o << " const unsigned opcode = MI.getOpcode();\n"
<< " if (Inst.getBitWidth() != " << BitWidth << ")\n"
<< " Inst = Inst.zext(" << BitWidth << ");\n"
<< " if (Scratch.getBitWidth() != " << BitWidth << ")\n"
<< " Scratch = Scratch.zext(" << BitWidth << ");\n"
<< " LoadIntFromMemory(Inst, (const uint8_t *)&InstBits[opcode * "
<< NumWords << "], " << NumBytes << ");\n"
<< " APInt &Value = Inst;\n"
<< " APInt &op = Scratch;\n"
<< " switch (opcode) {\n";
} else {
o << " const unsigned opcode = MI.getOpcode();\n"
<< " uint64_t Value = InstBits[opcode];\n"
<< " uint64_t op = 0;\n"
<< " (void)op; // suppress warning\n"
<< " switch (opcode) {\n";
}
// Construct all cases statement for each opcode
for (Record *R : Insts) {
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
R->getValueAsBit("isPseudo"))
continue;
std::string InstName =
(R->getValueAsString("Namespace") + "::" + R->getName()).str();
std::string Case = getInstructionCase(R, Target);

CaseMap[Case].push_back(std::move(InstName));
}

// Emit initial function code
if (UseAPInt) {
int NumWords = APInt::getNumWords(BitWidth);
int NumBytes = (BitWidth + 7) / 8;
o << " const unsigned opcode = MI.getOpcode();\n"
<< " if (Inst.getBitWidth() != " << BitWidth << ")\n"
<< " Inst = Inst.zext(" << BitWidth << ");\n"
<< " if (Scratch.getBitWidth() != " << BitWidth << ")\n"
<< " Scratch = Scratch.zext(" << BitWidth << ");\n"
<< " LoadIntFromMemory(Inst, (const uint8_t *)&InstBits[opcode * "
<< NumWords << "], " << NumBytes << ");\n"
<< " APInt &Value = Inst;\n"
<< " APInt &op = Scratch;\n"
<< " switch (opcode) {\n";
} else {
o << " const unsigned opcode = MI.getOpcode();\n"
<< " uint64_t Value = InstBits[opcode];\n"
<< " uint64_t op = 0;\n"
<< " (void)op; // suppress warning\n"
<< " switch (opcode) {\n";
}

// Emit each case statement
std::map<std::string, std::vector<std::string>>::iterator IE, EE;
for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
const std::string &Case = IE->first;
std::vector<std::string> &InstList = IE->second;
// Emit each case statement
std::map<std::string, std::vector<std::string>>::iterator IE, EE;
for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
const std::string &Case = IE->first;
std::vector<std::string> &InstList = IE->second;

for (int i = 0, N = InstList.size(); i < N; i++) {
if (i) o << "\n";
o << " case " << InstList[i] << ":";
for (int i = 0, N = InstList.size(); i < N; i++) {
if (i)
o << "\n";
o << " case " << InstList[i] << ":";
}
o << " {\n";
o << Case;
o << " break;\n"
<< " }\n";
}
o << " {\n";
o << Case;
o << " break;\n"
<< " }\n";
}

// Default case: unhandled opcode
o << " default:\n"
<< " std::string msg;\n"
<< " raw_string_ostream Msg(msg);\n"
<< " Msg << \"Not supported instr: \" << MI;\n"
<< " report_fatal_error(msg.c_str());\n"
<< " }\n";
if (UseAPInt)
o << " Inst = Value;\n";
else
o << " return Value;\n";
o << "}\n\n";
// Default case: unhandled opcode
o << " default:\n"
<< " std::string msg;\n"
<< " raw_string_ostream Msg(msg);\n"
<< " Msg << \"Not supported instr: \" << MI;\n"
<< " report_fatal_error(Msg.str().c_str());\n"
<< " }\n";
if (UseAPInt)
o << " Inst = Value;\n";
else
o << " return Value;\n";
o << "}\n\n";
}

const auto &All = SubtargetFeatureInfo::getAll(Records);
std::map<Record *, SubtargetFeatureInfo, LessRecordByID> SubtargetFeatures;
Expand Down
491 changes: 491 additions & 0 deletions llvm/utils/TableGen/VarLenCodeEmitterGen.cpp

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions llvm/utils/TableGen/VarLenCodeEmitterGen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- VarLenCodeEmitterGen.h - CEG for variable-length insts ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declare the CodeEmitterGen component for variable-length
// instructions. See the .cpp file for more details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H
#define LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H

namespace llvm {

class RecordKeeper;
class raw_ostream;

void emitVarLenCodeEmitter(RecordKeeper &R, raw_ostream &OS);

} // end namespace llvm
#endif