345 changes: 15 additions & 330 deletions llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,15 @@ static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo,
static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = IntRegDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
return DecodeIntRegsRegisterClass(Inst, RegNo, Address, Decoder);
}

// This is used for the type "ptr_rc", which is either IntRegs or I64Regs
// depending on SparcRegisterInfo::getPointerRegClass.
static DecodeStatus DecodePointerLikeRegClass0(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeIntRegsRegisterClass(Inst, RegNo, Address, Decoder);
}

static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst, unsigned RegNo,
Expand Down Expand Up @@ -195,9 +199,9 @@ static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}

static DecodeStatus DecodeCPRegsRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
static DecodeStatus
DecodeCoprocRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = CPRegDecoderTable[RegNo];
Expand Down Expand Up @@ -248,9 +252,9 @@ static DecodeStatus DecodeIntPairRegisterClass(MCInst &Inst, unsigned RegNo,
return S;
}

static DecodeStatus DecodeCPPairRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
static DecodeStatus
DecodeCoprocPairRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;

Expand All @@ -259,53 +263,10 @@ static DecodeStatus DecodeCPPairRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}

static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeCall(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeSIMM13(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeJMPL(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeSWAP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);
static DecodeStatus DecodeTRAP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);

#include "SparcGenDisassemblerTables.inc"

Expand Down Expand Up @@ -363,147 +324,6 @@ DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
return MCDisassembler::Fail;
}

typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder);

static DecodeStatus DecodeMem(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder, bool isLoad,
DecodeFunc DecodeRD) {
unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
bool isImm = fieldFromInstruction(insn, 13, 1);
bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
unsigned asi = fieldFromInstruction(insn, 5, 8);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);

DecodeStatus status;
if (isLoad) {
status = DecodeRD(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}

// Decode rs1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode imm|rs2.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}

if (hasAsi)
MI.addOperand(MCOperand::createImm(asi));

if (!isLoad) {
status = DecodeRD(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}

static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeIntRegsRegisterClass);
}

static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeIntPairRegisterClass);
}

static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeFPRegsRegisterClass);
}

static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeDFPRegsRegisterClass);
}

static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeQFPRegsRegisterClass);
}

static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeCPRegsRegisterClass);
}

static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeCPPairRegisterClass);
}

static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeIntRegsRegisterClass);
}

static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeIntPairRegisterClass);
}

static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeFPRegsRegisterClass);
}

static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeDFPRegsRegisterClass);
}

static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeQFPRegsRegisterClass);
}

static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeCPRegsRegisterClass);
}

static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn,
uint64_t Address,
const MCDisassembler *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeCPPairRegisterClass);
}

static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
uint64_t Address, uint64_t Offset,
uint64_t Width, MCInst &MI,
Expand All @@ -528,138 +348,3 @@ static DecodeStatus DecodeSIMM13(MCInst &MI, unsigned insn, uint64_t Address,
MI.addOperand(MCOperand::createImm(tgt));
return MCDisassembler::Success;
}

static DecodeStatus DecodeJMPL(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {

unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);

// Decode RD.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS1 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}

static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {

unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);

// Decode RS1.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS2 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}

static DecodeStatus DecodeSWAP(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {

unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
unsigned asi = fieldFromInstruction(insn, 5, 8);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);

// Decode RD.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS1 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}

if (hasAsi)
MI.addOperand(MCOperand::createImm(asi));

return MCDisassembler::Success;
}

static DecodeStatus DecodeTRAP(MCInst &MI, unsigned insn, uint64_t Address,
const MCDisassembler *Decoder) {

unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
unsigned cc =fieldFromInstruction(insn, 25, 4);
unsigned rs2 = 0;
unsigned imm7 = 0;
if (isImm)
imm7 = fieldFromInstruction(insn, 0, 7);
else
rs2 = fieldFromInstruction(insn, 0, 5);

// Decode RS1.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;

// Decode RS1 | IMM7.
if (isImm)
MI.addOperand(MCOperand::createImm(imm7));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}

// Decode CC
MI.addOperand(MCOperand::createImm(cc));

return MCDisassembler::Success;
}
9 changes: 3 additions & 6 deletions llvm/lib/Target/Sparc/SparcInstr64Bit.td
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ def UDIVXri : F3_2<2, 0b001101,
let Predicates = [Is64Bit] in {

// 64-bit loads.
let DecoderMethod = "DecodeLoadInt" in
defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;

let mayLoad = 1, isAsmParserOnly = 1 in {
def TLS_LDXrr : F3_1<3, 0b001011,
Expand Down Expand Up @@ -283,12 +282,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;

// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
let DecoderMethod = "DecodeLoadInt" in
defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;

// 64-bit stores.
let DecoderMethod = "DecodeStoreInt" in
defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;

// Truncating stores from i64 are identical to the i32 stores.
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
Expand Down
172 changes: 73 additions & 99 deletions llvm/lib/Target/Sparc/SparcInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ def SparcMEMriAsmOperand : AsmOperandClass {

def MEMrr : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc:$rs1, ptr_rc:$rs2);
let MIOperandInfo = (ops ptr_rc, ptr_rc);
let ParserMatchClass = SparcMEMrrAsmOperand;
}
def MEMri : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc:$rs1, i32imm:$simm13);
let MIOperandInfo = (ops ptr_rc, i32imm);
let ParserMatchClass = SparcMEMriAsmOperand;
}

Expand Down Expand Up @@ -561,38 +561,28 @@ let usesCustomInserter = 1, Uses = [FCC0] in {
}

// Section B.1 - Load Integer Instructions, p. 90
let DecoderMethod = "DecodeLoadInt" in {
defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8, IntRegs, i32>;
defm LDSH : LoadA<"ldsh", 0b001010, 0b011010, sextloadi16, IntRegs, i32>;
defm LDUB : LoadA<"ldub", 0b000001, 0b010001, zextloadi8, IntRegs, i32>;
defm LDUH : LoadA<"lduh", 0b000010, 0b010010, zextloadi16, IntRegs, i32>;
defm LD : LoadA<"ld", 0b000000, 0b010000, load, IntRegs, i32>;
}

let DecoderMethod = "DecodeLoadIntPair" in
defm LDD : LoadA<"ldd", 0b000011, 0b010011, load, IntPair, v2i32, IIC_ldd>;
defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8, IntRegs, i32>;
defm LDSH : LoadA<"ldsh", 0b001010, 0b011010, sextloadi16, IntRegs, i32>;
defm LDUB : LoadA<"ldub", 0b000001, 0b010001, zextloadi8, IntRegs, i32>;
defm LDUH : LoadA<"lduh", 0b000010, 0b010010, zextloadi16, IntRegs, i32>;
defm LD : LoadA<"ld", 0b000000, 0b010000, load, IntRegs, i32>;
defm LDD : LoadA<"ldd", 0b000011, 0b010011, load, IntPair, v2i32, IIC_ldd>;

// Section B.2 - Load Floating-point Instructions, p. 92
let DecoderMethod = "DecodeLoadFP" in {
defm LDF : Load<"ld", 0b100000, load, FPRegs, f32, IIC_iu_or_fpu_instr>;
def LDFArr : LoadASI<"ld", 0b110000, FPRegs>,
Requires<[HasV9]>;
}
let DecoderMethod = "DecodeLoadDFP" in {
defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64, IIC_ldd>;
def LDDFArr : LoadASI<"ldd", 0b110011, DFPRegs>,
Requires<[HasV9]>;
}
let DecoderMethod = "DecodeLoadQFP" in
defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>,
Requires<[HasV9, HasHardQuad]>;

let DecoderMethod = "DecodeLoadCP" in
defm LDC : Load<"ld", 0b110000, load, CoprocRegs, i32>;
let DecoderMethod = "DecodeLoadCPPair" in
defm LDDC : Load<"ldd", 0b110011, load, CoprocPair, v2i32, IIC_ldd>;

let DecoderMethod = "DecodeLoadCP", Defs = [CPSR] in {
defm LDF : Load<"ld", 0b100000, load, FPRegs, f32, IIC_iu_or_fpu_instr>;
def LDFArr : LoadASI<"ld", 0b110000, FPRegs>,
Requires<[HasV9]>;

defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64, IIC_ldd>;
def LDDFArr : LoadASI<"ldd", 0b110011, DFPRegs>,
Requires<[HasV9]>;
defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>,
Requires<[HasV9, HasHardQuad]>;

defm LDC : Load<"ld", 0b110000, load, CoprocRegs, i32>;
defm LDDC : Load<"ldd", 0b110011, load, CoprocPair, v2i32, IIC_ldd>;

let Defs = [CPSR] in {
let rd = 0 in {
def LDCSRrr : F3_1<3, 0b110001, (outs), (ins (MEMrr $rs1, $rs2):$addr),
"ld [$addr], %csr", []>;
Expand All @@ -601,21 +591,20 @@ let DecoderMethod = "DecodeLoadCP", Defs = [CPSR] in {
}
}

let DecoderMethod = "DecodeLoadFP" in
let Defs = [FSR] in {
let rd = 0 in {
def LDFSRrr : F3_1<3, 0b100001, (outs), (ins (MEMrr $rs1, $rs2):$addr),
"ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>;
def LDFSRri : F3_2<3, 0b100001, (outs), (ins (MEMri $rs1, $simm13):$addr),
"ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>;
}
let rd = 1 in {
def LDXFSRrr : F3_1<3, 0b100001, (outs), (ins (MEMrr $rs1, $rs2):$addr),
"ldx [$addr], %fsr", []>, Requires<[HasV9]>;
def LDXFSRri : F3_2<3, 0b100001, (outs), (ins (MEMri $rs1, $simm13):$addr),
"ldx [$addr], %fsr", []>, Requires<[HasV9]>;
}
let Defs = [FSR] in {
let rd = 0 in {
def LDFSRrr : F3_1<3, 0b100001, (outs), (ins (MEMrr $rs1, $rs2):$addr),
"ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>;
def LDFSRri : F3_2<3, 0b100001, (outs), (ins (MEMri $rs1, $simm13):$addr),
"ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>;
}
let rd = 1 in {
def LDXFSRrr : F3_1<3, 0b100001, (outs), (ins (MEMrr $rs1, $rs2):$addr),
"ldx [$addr], %fsr", []>, Requires<[HasV9]>;
def LDXFSRri : F3_2<3, 0b100001, (outs), (ins (MEMri $rs1, $simm13):$addr),
"ldx [$addr], %fsr", []>, Requires<[HasV9]>;
}
}

let mayLoad = 1, isAsmParserOnly = 1 in {
def GDOP_LDrr : F3_1<3, 0b000000,
Expand All @@ -627,37 +616,25 @@ let mayLoad = 1, isAsmParserOnly = 1 in {
}

// Section B.4 - Store Integer Instructions, p. 95
let DecoderMethod = "DecodeStoreInt" in {
defm STB : StoreA<"stb", 0b000101, 0b010101, truncstorei8, IntRegs, i32>;
defm STH : StoreA<"sth", 0b000110, 0b010110, truncstorei16, IntRegs, i32>;
defm ST : StoreA<"st", 0b000100, 0b010100, store, IntRegs, i32>;
}

let DecoderMethod = "DecodeStoreIntPair" in
defm STD : StoreA<"std", 0b000111, 0b010111, store, IntPair, v2i32>;
defm STB : StoreA<"stb", 0b000101, 0b010101, truncstorei8, IntRegs, i32>;
defm STH : StoreA<"sth", 0b000110, 0b010110, truncstorei16, IntRegs, i32>;
defm ST : StoreA<"st", 0b000100, 0b010100, store, IntRegs, i32>;
defm STD : StoreA<"std", 0b000111, 0b010111, store, IntPair, v2i32>;

// Section B.5 - Store Floating-point Instructions, p. 97
let DecoderMethod = "DecodeStoreFP" in {
defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
def STFArr : StoreASI<"st", 0b110100, FPRegs>,
Requires<[HasV9]>;
}
let DecoderMethod = "DecodeStoreDFP" in {
defm STDF : Store<"std", 0b100111, store, DFPRegs, f64, IIC_std>;
def STDFArr : StoreASI<"std", 0b110111, DFPRegs>,
Requires<[HasV9]>;
}
let DecoderMethod = "DecodeStoreQFP" in
defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>,
Requires<[HasV9, HasHardQuad]>;

let DecoderMethod = "DecodeStoreCP" in
defm STC : Store<"st", 0b110100, store, CoprocRegs, i32>;

let DecoderMethod = "DecodeStoreCPPair" in
defm STDC : Store<"std", 0b110111, store, CoprocPair, v2i32, IIC_std>;
defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
def STFArr : StoreASI<"st", 0b110100, FPRegs>,
Requires<[HasV9]>;
defm STDF : Store<"std", 0b100111, store, DFPRegs, f64, IIC_std>;
def STDFArr : StoreASI<"std", 0b110111, DFPRegs>,
Requires<[HasV9]>;
defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>,
Requires<[HasV9, HasHardQuad]>;

defm STC : Store<"st", 0b110100, store, CoprocRegs, i32>;
defm STDC : Store<"std", 0b110111, store, CoprocPair, v2i32, IIC_std>;

let DecoderMethod = "DecodeStoreCP", rd = 0 in {
let rd = 0 in {
let Defs = [CPSR] in {
def STCSRrr : F3_1<3, 0b110101, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"st %csr, [$addr]", [], IIC_st>;
Expand All @@ -672,32 +649,30 @@ let DecoderMethod = "DecodeStoreCP", rd = 0 in {
}
}

let DecoderMethod = "DecodeStoreFP" in {
let rd = 0 in {
let Defs = [FSR] in {
def STFSRrr : F3_1<3, 0b100101, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"st %fsr, [$addr]", [], IIC_st>;
def STFSRri : F3_2<3, 0b100101, (outs (MEMri $rs1, $simm13):$addr), (ins),
"st %fsr, [$addr]", [], IIC_st>;
}
let Defs = [FQ] in {
def STDFQrr : F3_1<3, 0b100110, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"std %fq, [$addr]", [], IIC_std>;
def STDFQri : F3_2<3, 0b100110, (outs (MEMri $rs1, $simm13):$addr), (ins),
"std %fq, [$addr]", [], IIC_std>;
}
let rd = 0 in {
let Defs = [FSR] in {
def STFSRrr : F3_1<3, 0b100101, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"st %fsr, [$addr]", [], IIC_st>;
def STFSRri : F3_2<3, 0b100101, (outs (MEMri $rs1, $simm13):$addr), (ins),
"st %fsr, [$addr]", [], IIC_st>;
}
let rd = 1, Defs = [FSR] in {
def STXFSRrr : F3_1<3, 0b100101, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"stx %fsr, [$addr]", []>, Requires<[HasV9]>;
def STXFSRri : F3_2<3, 0b100101, (outs (MEMri $rs1, $simm13):$addr), (ins),
"stx %fsr, [$addr]", []>, Requires<[HasV9]>;
let Defs = [FQ] in {
def STDFQrr : F3_1<3, 0b100110, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"std %fq, [$addr]", [], IIC_std>;
def STDFQri : F3_2<3, 0b100110, (outs (MEMri $rs1, $simm13):$addr), (ins),
"std %fq, [$addr]", [], IIC_std>;
}
}
let rd = 1, Defs = [FSR] in {
def STXFSRrr : F3_1<3, 0b100101, (outs (MEMrr $rs1, $rs2):$addr), (ins),
"stx %fsr, [$addr]", []>, Requires<[HasV9]>;
def STXFSRri : F3_2<3, 0b100101, (outs (MEMri $rs1, $simm13):$addr), (ins),
"stx %fsr, [$addr]", []>, Requires<[HasV9]>;
}

// Section B.8 - SWAP Register with Memory Instruction
// (Atomic swap)
let Constraints = "$val = $rd", DecoderMethod = "DecodeSWAP" in {
let Constraints = "$val = $rd" in {
def SWAPrr : F3_1<3, 0b001111,
(outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr, IntRegs:$val),
"swap [$addr], $rd",
Expand Down Expand Up @@ -1030,8 +1005,7 @@ let Uses = [O6],
// Section B.25 - Jump and Link Instruction

// JMPL Instruction.
let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1,
DecoderMethod = "DecodeJMPL" in {
let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in {
def JMPLrr: F3_1<2, 0b111000,
(outs IntRegs:$rd), (ins (MEMrr $rs1, $rs2):$addr),
"jmpl $addr, $rd",
Expand Down Expand Up @@ -1065,7 +1039,7 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1,

// Section B.26 - Return from Trap Instruction
let isReturn = 1, isTerminator = 1, hasDelaySlot = 1,
isBarrier = 1, rd = 0, DecoderMethod = "DecodeReturn" in {
isBarrier = 1, rd = 0 in {
def RETTrr : F3_1<2, 0b111001,
(outs), (ins (MEMrr $rs1, $rs2):$addr),
"rett $addr",
Expand All @@ -1081,7 +1055,7 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = 1,

// Section B.27 - Trap on Integer Condition Codes Instruction
// conditional branch class:
let DecoderNamespace = "SparcV8", DecoderMethod = "DecodeTRAP", hasSideEffects = 1, Uses = [ICC], cc = 0b00 in
let DecoderNamespace = "SparcV8", hasSideEffects = 1, Uses = [ICC], cc = 0b00 in
{
def TRAPrr : TRAPSPrr<0b111010,
(outs), (ins IntRegs:$rs1, IntRegs:$rs2, CCOp:$cond),
Expand All @@ -1104,7 +1078,7 @@ multiclass TRAP<string regStr> {
[]>;
}

let DecoderNamespace = "SparcV9", DecoderMethod = "DecodeTRAP", Predicates = [HasV9], hasSideEffects = 1, Uses = [ICC], cc = 0b00 in
let DecoderNamespace = "SparcV9", Predicates = [HasV9], hasSideEffects = 1, Uses = [ICC], cc = 0b00 in
defm TICC : TRAP<"%icc">;


Expand Down
85 changes: 85 additions & 0 deletions llvm/test/MC/Disassembler/Sparc/sparc-coproc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# RUN: llvm-mc --disassemble %s -triple=sparc-unknown-linux | FileCheck %s

# CHECK: ld [%i0+%l6], %c10
0xd5 0x86 0x00 0x16

# CHECK: ld [%i0+32], %c10
0xd5 0x86 0x20 0x20

# CHECK: ld [%g1], %c10
0xd5 0x80 0x60 0x00

# CHECK: ld [%g1], %c10
0xd5 0x80 0x40 0x00

# CHECK: st %c10, [%i0+%l6]
0xd5 0xa6 0x00 0x16

# CHECK: st %c10, [%i0+32]
0xd5 0xa6 0x20 0x20

# CHECK: st %c10, [%g1]
0xd5 0xa0 0x60 0x00

# CHECK: st %c10, [%g1]
0xd5 0xa0 0x40 0x00

# CHECK: ldd [%i0+%l6], %c10
0xd5 0x9e 0x00 0x16

# CHECK: ldd [%i0+32], %c10
0xd5 0x9e 0x20 0x20

# CHECK: ldd [%g1], %c10
0xd5 0x98 0x60 0x00

# CHECK: ldd [%g1], %c10
0xd5 0x98 0x40 0x00

# CHECK: std %c10, [%i0+%l6]
0xd5 0xbe 0x00 0x16

# CHECK: std %c10, [%i0+32]
0xd5 0xbe 0x20 0x20

# CHECK: std %c10, [%g1]
0xd5 0xb8 0x60 0x00

# CHECK: std %c10, [%g1]
0xd5 0xb8 0x40 0x00

# CHECK: ld [%i0+%l6], %csr
0xc1 0x8e 0x00 0x16

# CHECK: ld [%i0+32], %csr
0xc1 0x8e 0x20 0x20

# CHECK: ld [%g1], %csr
0xc1 0x88 0x60 0x00

# CHECK: ld [%g1], %csr
0xc1 0x88 0x40 0x00

# CHECK: st %csr, [%i0+%l6]
0xc1 0xae 0x00 0x16

# CHECK: st %csr, [%i0+32]
0xc1 0xae 0x20 0x20

# CHECK: st %csr, [%g1]
0xc1 0xa8 0x60 0x00

# CHECK: st %csr, [%g1]
0xc1 0xa8 0x40 0x00

# CHECK: std %cq, [%i0+%l6]
0xc1 0xb6 0x00 0x16

# CHECK: std %cq, [%i0+32]
0xc1 0xb6 0x20 0x20

# CHECK: std %cq, [%g1]
0xc1 0xb0 0x60 0x00

# CHECK: std %cq, [%g1]
0xc1 0xb0 0x40 0x00
117 changes: 117 additions & 0 deletions llvm/test/MC/Disassembler/Sparc/sparc-mem.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
# CHECK: ldsb [%g1], %o4
0xd8 0x48 0x40 0x00

# CHECK: ldsba [%i0+%l6] 131, %o2
0xd4 0xce 0x10 0x76

# CHECK: ldsh [%i0+%l6], %o2
0xd4 0x56 0x00 0x16

Expand All @@ -24,6 +27,9 @@
# CHECK: ldsh [%g1], %o4
0xd8 0x50 0x40 0x00

# CHECK: ldsha [%i0+%l6] 131, %o2
0xd4 0xd6 0x10 0x76

# CHECK: ldub [%i0+%l6], %o2
0xd4 0x0e 0x00 0x16

Expand All @@ -36,6 +42,9 @@
# CHECK: ldub [%g1], %o2
0xd4 0x08 0x40 0x00

# CHECK: lduba [%i0+%l6] 131, %o2
0xd4 0x8e 0x10 0x76

# CHECK: lduh [%i0+%l6], %o2
0xd4 0x16 0x00 0x16

Expand All @@ -48,6 +57,9 @@
# CHECK: lduh [%g1], %o2
0xd4 0x10 0x40 0x00

# CHECK: lduha [%i0+%l6] 131, %o2
0xd4 0x96 0x10 0x76

# CHECK: ld [%i0+%l6], %o2
0xd4 0x06 0x00 0x16

Expand All @@ -60,6 +72,9 @@
# CHECK: ld [%g1], %o2
0xd4 0x00 0x40 0x00

# CHECK: lda [%i0+%l6] 131, %o2
0xd4 0x86 0x10 0x76

# CHECK: ld [%i0+%l6], %f2
0xc5 0x06 0x00 0x16

Expand All @@ -72,6 +87,9 @@
# CHECK: ld [%g1], %f2
0xc5 0x00 0x40 0x00

# CHECK: lda [%i0+%l6] 131, %f2
0xc5 0x86 0x10 0x76

# CHECK: ldd [%i0+%l6], %f2
0xc5 0x1e 0x00 0x16

Expand All @@ -84,6 +102,9 @@
# CHECK: ldd [%g1], %f2
0xc5 0x18 0x40 0x00

# CHECK: ldda [%i0+%l6] 131, %f2
0xc5 0x9e 0x10 0x76

# CHECK: ldq [%i0+%l6], %f4
0xc9 0x16 0x00 0x16

Expand Down Expand Up @@ -132,6 +153,9 @@
# CHECK: stb %o2, [%g1]
0xd4 0x28 0x40 0x00

# CHECK: stba %o2, [%i0+%l6] 131
0xd4 0xae 0x10 0x76

# CHECK: sth %o2, [%i0+%l6]
0xd4 0x36 0x00 0x16

Expand All @@ -144,6 +168,9 @@
# CHECK: sth %o2, [%g1]
0xd4 0x30 0x40 0x00

# CHECK: stha %o2, [%i0+%l6] 131
0xd4 0xb6 0x10 0x76

# CHECK: st %o2, [%i0+%l6]
0xd4 0x26 0x00 0x16

Expand All @@ -156,6 +183,9 @@
# CHECK: st %o2, [%g1]
0xd4 0x20 0x40 0x00

# CHECK: sta %o2, [%i0+%l6] 131
0xd4 0xa6 0x10 0x76

# CHECK: st %f2, [%i0+%l6]
0xc5 0x26 0x00 0x16

Expand All @@ -168,6 +198,9 @@
# CHECK: st %f2, [%g1]
0xc5 0x20 0x40 0x00

# CHECK: sta %f2, [%i0+%l6] 131
0xc5 0xa6 0x10 0x76

# CHECK: std %f2, [%i0+%l6]
0xc5 0x3e 0x00 0x16

Expand All @@ -180,6 +213,9 @@
# CHECK: std %f2, [%g1]
0xc5 0x38 0x40 0x00

# CHECK: stda %f2, [%i0+%l6] 131
0xc5 0xbe 0x10 0x76

# CHECK: stq %f4, [%i0+%l6]
0xc9 0x36 0x00 0x16

Expand Down Expand Up @@ -245,3 +281,84 @@

# CHECK: std %o2, [%g1]
0xd4 0x38 0x40 0x00

# CHECK: stda %o2, [%i0+%l6] 131
0xd4 0xbe 0x10 0x76

# CHECK: ldstub [%i0+%l6], %o2
0xd4 0x6e 0x00 0x16

# CHECK: ldstub [%i0+32], %o2
0xd4 0x6e 0x20 0x20

# CHECK: ldstub [%g1], %o2
0xd4 0x68 0x60 0x00

# CHECK: ldstub [%g1], %o2
0xd4 0x68 0x40 0x00

# CHECK: ldstuba [%i0+%l6] 131, %o2
0xd4 0xee 0x10 0x76

# CHECK: ldstuba [%g1] 131, %o2
0xd4 0xe8 0x50 0x60

# CHECK: flush %g1+%g2
0x81 0xd8 0x40 0x02

# CHECK: flush %g1+8
0x81 0xd8 0x60 0x08

# CHECK: flush %g1
0x81 0xd8 0x40 0x00

# CHECK: flush %g1
0x81 0xd8 0x60 0x00

# CHECK: ld [%i0+%l6], %fsr
0xc1 0x0e 0x00 0x16

# CHECK: ld [%i0+32], %fsr
0xc1 0x0e 0x20 0x20

# CHECK: ld [%g1], %fsr
0xc1 0x08 0x60 0x00

# CHECK: ld [%g1], %fsr
0xc1 0x08 0x40 0x00

# CHECK: st %fsr, [%i0+%l6]
0xc1 0x2e 0x00 0x16

# CHECK: st %fsr, [%i0+32]
0xc1 0x2e 0x20 0x20

# CHECK: st %fsr, [%g1]
0xc1 0x28 0x60 0x00

# CHECK: st %fsr, [%g1]
0xc1 0x28 0x40 0x00

# CHECK: ldx [%i0+%l6], %fsr
0xc3 0x0e 0x00 0x16

# CHECK: ldx [%i0+32], %fsr
0xc3 0x0e 0x20 0x20

# CHECK: ldx [%g1], %fsr
0xc3 0x08 0x60 0x00

# CHECK: ldx [%g1], %fsr
0xc3 0x08 0x40 0x00

# CHECK: stx %fsr, [%i0+%l6]
0xc3 0x2e 0x00 0x16

# CHECK: stx %fsr, [%i0+32]
0xc3 0x2e 0x20 0x20

# CHECK: stx %fsr, [%g1]
0xc3 0x28 0x60 0x00

# CHECK: stx %fsr, [%g1]
0xc3 0x28 0x40 0x00
6 changes: 0 additions & 6 deletions llvm/test/MC/Disassembler/Sparc/sparc-special-registers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,5 @@
# CHECK: st %fsr, [%i5]
0xc1 0x2f 0x40 0x00

# CHECK: st %csr, [%i5]
0xc1 0xaf 0x40 0x00

# CHECK: std %cq, [%o3+-93]
0xc1 0xb2 0xff 0xa3

# CHECK: std %fq, [%i5+%l1]
0xc1 0x37 0x40 0x11
6 changes: 6 additions & 0 deletions llvm/test/MC/Disassembler/Sparc/sparc-v9.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@

# CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync
0x81 0x43 0xe0 0x7f

# CHECK: prefetch [%i1+3968], 1
0xc3,0x6e,0x6f,0x80

# CHECK: prefetch [%i1+%i2], 1
0xc3,0x6e,0x40,0x1a
3 changes: 3 additions & 0 deletions llvm/test/MC/Disassembler/Sparc/sparc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@
# CHECK: rett %i7+8
0x81 0xcf 0xe0 0x08

# CHECK: rett %i7+%i0
0x81 0xcf 0xc0 0x18

# CHECK: stbar
0x81 0x43 0xc0 0x00

Expand Down
63 changes: 63 additions & 0 deletions llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// RUN: not llvm-tblgen -gen-disassembler -I %p/../../../include %s 2>&1 | FileCheck %s --implicit-check-not=error:

include "llvm/Target/Target.td"

def ArchInstrInfo : InstrInfo { }

def Arch : Target {
let InstructionSet = ArchInstrInfo;
}

def Reg : Register<"reg">;

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

def complex_nodec : Operand<i32> {
let MIOperandInfo = (ops Regs, Regs);
}

def complex_withdec : Operand<i32> {
let MIOperandInfo = (ops Regs, Regs);
let DecoderMethod = "DecodeComplex";
}

class ArchInstr : Instruction {
let Size = 1;
bits<8> Inst;
}

// This definition is broken in both directions:
// 1. Uses a complex operand without a decoder, and without named sub-ops.
// 2. Uses a complex operand with named sub-ops, but with a decoder as well.

// CHECK: error: DecoderEmitter: operand "r1c" uses MIOperandInfo with multiple ops, but doesn't have a custom decoder!
// CHECK: note: Dumping record for previous error:
// CHECK: error: DecoderEmitter: operand "r1ab" has type "complex_withdec" with a custom DecoderMethod, but also named sub-operands.
def foo1 : ArchInstr {
bits<2> r1a;
bits<2> r1b;
bits<2> r1c;

let Inst{1-0} = r1a;
let Inst{3-2} = r1b;
let Inst{5-4} = r1c;
let Inst{7-6} = 0b00;

let OutOperandList = (outs complex_nodec:$r1c);
let InOperandList = (ins (complex_withdec $r1a, $r1b):$r1ab);
}

// This definition has no errors.
def foo2 : ArchInstr {
bits<2> r2a;
bits<2> r2b;
bits<2> r2c;

let Inst{1-0} = r2a;
let Inst{3-2} = r2b;
let Inst{5-4} = r2c;
let Inst{7-6} = 0b01;

let OutOperandList = (outs complex_withdec:$r2c);
let InOperandList = (ins (complex_nodec $r2a, $r2b):$r2ab);
}
34 changes: 32 additions & 2 deletions llvm/test/TableGen/RegisterEncoder.td
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def RegOperand : RegisterOperand<RegClass> {
let EncoderMethod = "barEncoder";
}

def foo : Instruction {
def foo1 : Instruction {
let Size = 1;

let OutOperandList = (outs);
Expand All @@ -28,9 +28,39 @@ def foo : Instruction {
bits<8> Inst = bar;
}

// CHECK: case ::foo: {
// CHECK: case ::foo1: {
// CHECK: op = barEncoder
// CHECK: op &= UINT64_C(255);
// CHECK: Value |= op;
// CHECK: break;
// CHECK: }


// Also check that it works from a complex operand.

def RegPair : Operand<i32> {
let MIOperandInfo = (ops RegOperand, RegOperand);
}

def foo2 : Instruction {
let Size = 1;

let OutOperandList = (outs);
let InOperandList = (ins (RegPair $r1, $r2):$r12);

bits<4> r1;
bits<4> r2;
bits<8> Inst;
let Inst{3-0} = r1;
let Inst{7-4} = r2;
}

// CHECK: case ::foo2: {
// CHECK: op = barEncoder
// CHECK: op &= UINT64_C(15);
// CHECK: Value |= op;
// CHECK: op = barEncoder
// CHECK: op &= UINT64_C(15);
// CHECK: Value |= op;
// CHECK: break;
// CHECK: }
35 changes: 16 additions & 19 deletions llvm/utils/TableGen/CodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <cassert>
#include <cstdint>
#include <map>
#include <set>
Expand Down Expand Up @@ -113,8 +112,6 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
} else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
// Get the machine operand number for the indicated operand.
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
"Explicitly used operand also marked as not emitted!");
} else {
// Fall back to positional lookup. By default, we now disable positional
// lookup (and print an error, below), but even so, we'll do the lookup to
Expand Down Expand Up @@ -164,30 +161,30 @@ bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
}
}

if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
PrintError(R, "Operand " + VarName + " used but also marked as not emitted!");
return false;
}

std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;
std::string &EncoderMethodName =
CGI.Operands[SO.first].EncoderMethodNames[SO.second];

if (UseAPInt)
Case += " op.clearAllBits();\n";

// If the source operand has a custom encoder, use it. This will
// get the encoding for all of the suboperands.
Case += " // op: " + VarName + "\n";

// If the source operand has a custom encoder, use it.
if (!EncoderMethodName.empty()) {
// A custom encoder has all of the information for the
// sub-operands, if there are more than one, so only
// query the encoder once per source operand.
if (SO.second == 0) {
Case += " // op: " + VarName + "\n";
if (UseAPInt) {
Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx);
Case += ", op";
} else {
Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
}
Case += ", Fixups, STI);\n";
if (UseAPInt) {
Case += " " + EncoderMethodName + "(MI, " + utostr(OpIdx);
Case += ", op";
} else {
Case += " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
}
Case += ", Fixups, STI);\n";
} else {
Case += " // op: " + VarName + "\n";
if (UseAPInt) {
Case += " getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
Case += ", op, Fixups, STI";
Expand Down
33 changes: 21 additions & 12 deletions llvm/utils/TableGen/CodeGenInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,11 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
} else if (Rec->isSubClassOf("RegisterClass")) {
OperandType = "OPERAND_REGISTER";
} else if (!Rec->isSubClassOf("PointerLikeRegClass") &&
!Rec->isSubClassOf("unknown_class"))
!Rec->isSubClassOf("unknown_class")) {
PrintFatalError(R->getLoc(), "Unknown operand class '" + Rec->getName() +
"' in '" + R->getName() +
"' instruction!");
}

// Check that the operand has a name and that it's unique.
if (ArgName.empty())
Expand All @@ -136,6 +137,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
Twine(i) +
" has the same name as a previous operand!");

OperandInfo &OpInfo = OperandList.emplace_back(
Rec, std::string(ArgName), std::string(PrintMethod),
OperandNamespace + "::" + OperandType, MIOperandNo, NumOps, MIOpInfo);

if (SubArgDag) {
if (SubArgDag->getNumArgs() != NumOps) {
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
Expand All @@ -162,24 +167,30 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
"In instruction '" + R->getName() + "', operand #" +
Twine(i) + " sub-arg #" + Twine(j) +
" has the same name as a previous operand!");

if (auto MaybeEncoderMethod =
cast<DefInit>(MIOpInfo->getArg(j))
->getDef()
->getValueAsOptionalString("EncoderMethod")) {
OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod;
}

OpInfo.SubOpNames[j] = SubArgName;
SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j);
}
} else if (!EncoderMethod.empty()) {
// If we have no explicit sub-op dag, but have an top-level encoder
// method, the single encoder will multiple sub-ops, itself.
OpInfo.EncoderMethodNames[0] = EncoderMethod;
for (unsigned j = 1; j < NumOps; ++j)
OpInfo.DoNotEncode[j] = true;
}

OperandList.emplace_back(
Rec, std::string(ArgName), std::string(PrintMethod),
std::string(EncoderMethod), OperandNamespace + "::" + OperandType,
MIOperandNo, NumOps, MIOpInfo);
MIOperandNo += NumOps;
}

if (VariadicOuts)
--NumDefs;

// Make sure the constraints list for each operand is large enough to hold
// constraint info, even if none is present.
for (OperandInfo &OpInfo : OperandList)
OpInfo.Constraints.resize(OpInfo.MINumOperands);
}


Expand Down Expand Up @@ -409,8 +420,6 @@ void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) {
std::pair<unsigned,unsigned> Op = ParseOperandName(OpName, false);

// Mark the operand as not-to-be encoded.
if (Op.second >= OperandList[Op.first].DoNotEncode.size())
OperandList[Op.first].DoNotEncode.resize(Op.second+1);
OperandList[Op.first].DoNotEncode[Op.second] = true;
}

Expand Down
21 changes: 12 additions & 9 deletions llvm/utils/TableGen/CodeGenInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,16 @@ template <typename T> class ArrayRef;
/// otherwise, it's empty.
std::string Name;

/// The names of sub-operands, if given, otherwise empty.
std::vector<std::string> SubOpNames;

/// PrinterMethodName - The method used to print operands of this type in
/// the asmprinter.
std::string PrinterMethodName;

/// EncoderMethodName - The method used to get the machine operand value
/// for binary encoding. "getMachineOpValue" by default.
std::string EncoderMethodName;
/// The method used to get the machine operand value for binary
/// encoding, per sub-operand. If empty, uses "getMachineOpValue".
std::vector<std::string> EncoderMethodNames;

/// OperandType - A value from MCOI::OperandType representing the type of
/// the operand.
Expand Down Expand Up @@ -119,12 +122,12 @@ template <typename T> class ArrayRef;
std::vector<ConstraintInfo> Constraints;

OperandInfo(Record *R, const std::string &N, const std::string &PMN,
const std::string &EMN, const std::string &OT, unsigned MION,
unsigned MINO, DagInit *MIOI)
: Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN),
OperandType(OT), MIOperandNo(MION), MINumOperands(MINO),
MIOperandInfo(MIOI) {}

const std::string &OT, unsigned MION, unsigned MINO,
DagInit *MIOI)
: Rec(R), Name(N), SubOpNames(MINO), PrinterMethodName(PMN),
EncoderMethodNames(MINO), OperandType(OT), MIOperandNo(MION),
MINumOperands(MINO), DoNotEncode(MINO), MIOperandInfo(MIOI),
Constraints(MINO) {}

/// getTiedOperand - If this operand is tied to another one, return the
/// other operand number. Otherwise, return -1.
Expand Down
113 changes: 98 additions & 15 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,18 @@ void parseVarLenInstOperand(const Record &Def,
}
}

static void debugDumpRecord(const Record &Rec) {
// Dump the record, so we can see what's going on...
std::string E;
raw_string_ostream S(E);
S << "Dumping record for previous error:\n";
S << Rec;
PrintNote(E);
}

/// For an operand field named OpName: populate OpInfo.InitValue with the
/// constant-valued bit values, and OpInfo.Fields with the ranges of bits to
/// insert from the decoded instruction.
static void addOneOperandFields(const Record &EncodingDef, const BitsInit &Bits,
std::map<std::string, std::string> &TiedNames,
StringRef OpName, OperandInfo &OpInfo) {
Expand Down Expand Up @@ -1991,14 +2003,23 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
// operands that are not explicitly represented in the encoding.
std::map<std::string, std::string> TiedNames;
for (unsigned i = 0; i < CGI.Operands.size(); ++i) {
int tiedTo = CGI.Operands[i].getTiedRegister();
if (tiedTo != -1) {
std::pair<unsigned, unsigned> SO =
CGI.Operands.getSubOperandNumber(tiedTo);
TiedNames[std::string(InOutOperands[i].second)] =
std::string(InOutOperands[SO.first].second);
TiedNames[std::string(InOutOperands[SO.first].second)] =
std::string(InOutOperands[i].second);
auto &Op = CGI.Operands[i];
for (unsigned j = 0; j < Op.Constraints.size(); ++j) {
const CGIOperandList::ConstraintInfo &CI = Op.Constraints[j];
if (CI.isTied()) {
int tiedTo = CI.getTiedOperand();
std::pair<unsigned, unsigned> SO =
CGI.Operands.getSubOperandNumber(tiedTo);
std::string TiedName = CGI.Operands[SO.first].SubOpNames[SO.second];
if (TiedName.empty())
TiedName = CGI.Operands[SO.first].Name;
std::string MyName = Op.SubOpNames[j];
if (MyName.empty())
MyName = Op.Name;

TiedNames[MyName] = TiedName;
TiedNames[TiedName] = MyName;
}
}
}

Expand Down Expand Up @@ -2054,7 +2075,9 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,

// Skip variables that correspond to explicitly-named operands.
unsigned OpIdx;
if (CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
std::pair<unsigned, unsigned> SubOp;
if (CGI.Operands.hasSubOperandAlias(Vals[i].getName(), SubOp) ||
CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx))
continue;

// Get the bit range for this operand:
Expand Down Expand Up @@ -2190,15 +2213,75 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
}
}

// At this point, we can locate the decoder field, but we need to know how
// to interpret it. As a first step, require the target to provide
// callbacks for decoding register classes.
// We're ready to find the instruction encoding locations for this operand.

// First, find the operand type ("OpInit"), and sub-op names
// ("SubArgDag") if present.
DagInit *SubArgDag = dyn_cast<DagInit>(OpInit);
if (SubArgDag)
OpInit = SubArgDag->getOperator();
Record *OpTypeRec = cast<DefInit>(OpInit)->getDef();
// Lookup the sub-operands from the operand type record (note that only
// Operand subclasses have MIOperandInfo, see CodeGenInstruction.cpp).
DagInit *SubOps = OpTypeRec->isSubClassOf("Operand")
? OpTypeRec->getValueAsDag("MIOperandInfo")
: nullptr;

// Lookup the decoder method and construct a new OperandInfo to hold our result.
OperandInfo OpInfo = getOpInfo(OpTypeRec);

// If we have named sub-operands...
if (SubArgDag) {
// Then there should not be a custom decoder specified on the top-level
// type.
if (!OpInfo.Decoder.empty()) {
PrintError(EncodingDef.getLoc(),
"DecoderEmitter: operand \"" + OpName + "\" has type \"" +
OpInit->getAsString() +
"\" with a custom DecoderMethod, but also named "
"sub-operands.");
continue;
}

// Decode each of the sub-ops separately.
assert(SubOps && SubArgDag->getNumArgs() == SubOps->getNumArgs());
for (unsigned i = 0; i < SubOps->getNumArgs(); ++i) {
StringRef SubOpName = SubArgDag->getArgNameStr(i);
OperandInfo SubOpInfo =
getOpInfo(cast<DefInit>(SubOps->getArg(i))->getDef());

if (DagInit *Dag = dyn_cast<DagInit>(OpInit))
OpInit = Dag->getOperator();
OperandInfo OpInfo = getOpInfo(cast<DefInit>(OpInit)->getDef());
addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpName,
SubOpInfo);
InsnOperands.push_back(SubOpInfo);
}
continue;
}

// Otherwise, if we have an operand with sub-operands, but they aren't
// named...
if (SubOps && OpInfo.Decoder.empty()) {
// If it's a single sub-operand, and no custom decoder, use the decoder
// from the one sub-operand.
if (SubOps->getNumArgs() == 1)
OpInfo = getOpInfo(cast<DefInit>(SubOps->getArg(0))->getDef());

// If we have multiple sub-ops, there'd better have a custom
// decoder. (Otherwise we don't know how to populate them properly...)
if (SubOps->getNumArgs() > 1) {
PrintError(EncodingDef.getLoc(),
"DecoderEmitter: operand \"" + OpName +
"\" uses MIOperandInfo with multiple ops, but doesn't "
"have a custom decoder!");
debugDumpRecord(EncodingDef);
continue;
}
}

addOneOperandFields(EncodingDef, Bits, TiedNames, OpName, OpInfo);
// FIXME: it should be an error not to find a definition for a given
// operand, rather than just failing to add it to the resulting
// instruction! (This is a longstanding bug, which will be addressed in an
// upcoming change.)
if (OpInfo.numFields() > 0)
InsnOperands.push_back(OpInfo);
}
Expand Down
3 changes: 2 additions & 1 deletion llvm/utils/TableGen/VarLenCodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,8 @@ std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding(

auto OpIdx = CGI.Operands.ParseOperandName(OperandName);
unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx);
StringRef CustomEncoder = CGI.Operands[OpIdx.first].EncoderMethodName;
StringRef CustomEncoder =
CGI.Operands[OpIdx.first].EncoderMethodNames[OpIdx.second];
if (ES.CustomEncoder.size())
CustomEncoder = ES.CustomEncoder;

Expand Down