Skip to content

Commit

Permalink
[llvm-exegesis][PowerPC] Add more register classes
Browse files Browse the repository at this point in the history
This PR adds more register class support in PowerPC,
mark OperandType for imm and memory operands.

Also added more unit tests for SnippetGenerator.

Reviewed By: #powerpc, steven.zhang

Differential Revision: https://reviews.llvm.org/D88044
  • Loading branch information
Jinsong Ji committed Dec 4, 2020
1 parent 2c66b6e commit c8ec685
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 1 deletion.
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstr64Bit.td
Expand Up @@ -19,12 +19,14 @@ def s16imm64 : Operand<i64> {
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS16ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def u16imm64 : Operand<i64> {
let PrintMethod = "printU16ImmOperand";
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCU16ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def s17imm64 : Operand<i64> {
// This operand type is used for addis/lis to allow the assembler parser
Expand All @@ -34,6 +36,7 @@ def s17imm64 : Operand<i64> {
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS17ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def tocentry : Operand<iPTR> {
let MIOperandInfo = (ops i64imm:$imm);
Expand Down
26 changes: 26 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Expand Up @@ -666,6 +666,7 @@ def PPCU1ImmAsmOperand : AsmOperandClass {
def u1imm : Operand<i32> {
let PrintMethod = "printU1ImmOperand";
let ParserMatchClass = PPCU1ImmAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}

def PPCU2ImmAsmOperand : AsmOperandClass {
Expand All @@ -675,6 +676,7 @@ def PPCU2ImmAsmOperand : AsmOperandClass {
def u2imm : Operand<i32> {
let PrintMethod = "printU2ImmOperand";
let ParserMatchClass = PPCU2ImmAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}

def PPCATBitsAsHintAsmOperand : AsmOperandClass {
Expand All @@ -684,6 +686,7 @@ def PPCATBitsAsHintAsmOperand : AsmOperandClass {
def atimm : Operand<i32> {
let PrintMethod = "printATBitsAsHint";
let ParserMatchClass = PPCATBitsAsHintAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}

def PPCU3ImmAsmOperand : AsmOperandClass {
Expand All @@ -693,6 +696,7 @@ def PPCU3ImmAsmOperand : AsmOperandClass {
def u3imm : Operand<i32> {
let PrintMethod = "printU3ImmOperand";
let ParserMatchClass = PPCU3ImmAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}

def PPCU4ImmAsmOperand : AsmOperandClass {
Expand All @@ -702,6 +706,7 @@ def PPCU4ImmAsmOperand : AsmOperandClass {
def u4imm : Operand<i32> {
let PrintMethod = "printU4ImmOperand";
let ParserMatchClass = PPCU4ImmAsmOperand;
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCS5ImmAsmOperand : AsmOperandClass {
let Name = "S5Imm"; let PredicateMethod = "isS5Imm";
Expand All @@ -711,6 +716,7 @@ def s5imm : Operand<i32> {
let PrintMethod = "printS5ImmOperand";
let ParserMatchClass = PPCS5ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<5>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU5ImmAsmOperand : AsmOperandClass {
let Name = "U5Imm"; let PredicateMethod = "isU5Imm";
Expand All @@ -720,6 +726,7 @@ def u5imm : Operand<i32> {
let PrintMethod = "printU5ImmOperand";
let ParserMatchClass = PPCU5ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU6ImmAsmOperand : AsmOperandClass {
let Name = "U6Imm"; let PredicateMethod = "isU6Imm";
Expand All @@ -729,6 +736,7 @@ def u6imm : Operand<i32> {
let PrintMethod = "printU6ImmOperand";
let ParserMatchClass = PPCU6ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<6>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU7ImmAsmOperand : AsmOperandClass {
let Name = "U7Imm"; let PredicateMethod = "isU7Imm";
Expand All @@ -738,6 +746,7 @@ def u7imm : Operand<i32> {
let PrintMethod = "printU7ImmOperand";
let ParserMatchClass = PPCU7ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<7>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU8ImmAsmOperand : AsmOperandClass {
let Name = "U8Imm"; let PredicateMethod = "isU8Imm";
Expand All @@ -747,6 +756,7 @@ def u8imm : Operand<i32> {
let PrintMethod = "printU8ImmOperand";
let ParserMatchClass = PPCU8ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<8>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU10ImmAsmOperand : AsmOperandClass {
let Name = "U10Imm"; let PredicateMethod = "isU10Imm";
Expand All @@ -756,6 +766,7 @@ def u10imm : Operand<i32> {
let PrintMethod = "printU10ImmOperand";
let ParserMatchClass = PPCU10ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<10>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU12ImmAsmOperand : AsmOperandClass {
let Name = "U12Imm"; let PredicateMethod = "isU12Imm";
Expand All @@ -765,6 +776,7 @@ def u12imm : Operand<i32> {
let PrintMethod = "printU12ImmOperand";
let ParserMatchClass = PPCU12ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<12>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCS16ImmAsmOperand : AsmOperandClass {
let Name = "S16Imm"; let PredicateMethod = "isS16Imm";
Expand All @@ -775,6 +787,7 @@ def s16imm : Operand<i32> {
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS16ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCU16ImmAsmOperand : AsmOperandClass {
let Name = "U16Imm"; let PredicateMethod = "isU16Imm";
Expand All @@ -785,6 +798,7 @@ def u16imm : Operand<i32> {
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCU16ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCS17ImmAsmOperand : AsmOperandClass {
let Name = "S17Imm"; let PredicateMethod = "isS17Imm";
Expand All @@ -798,6 +812,7 @@ def s17imm : Operand<i32> {
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS17ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCS34ImmAsmOperand : AsmOperandClass {
let Name = "S34Imm";
Expand All @@ -809,12 +824,14 @@ def s34imm : Operand<i64> {
let EncoderMethod = "getImm34EncodingNoPCRel";
let ParserMatchClass = PPCS34ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<34>";
let OperandType = "OPERAND_IMMEDIATE";
}
def s34imm_pcrel : Operand<i64> {
let PrintMethod = "printS34ImmOperand";
let EncoderMethod = "getImm34EncodingPCRel";
let ParserMatchClass = PPCS34ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<34>";
let OperandType = "OPERAND_IMMEDIATE";
}
def PPCImmZeroAsmOperand : AsmOperandClass {
let Name = "ImmZero";
Expand All @@ -825,6 +842,7 @@ def immZero : Operand<i32> {
let PrintMethod = "printImmZeroOperand";
let ParserMatchClass = PPCImmZeroAsmOperand;
let DecoderMethod = "decodeImmZeroOperand";
let OperandType = "OPERAND_IMMEDIATE";
}

def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;
Expand Down Expand Up @@ -970,47 +988,55 @@ def memri : Operand<iPTR> {
let MIOperandInfo = (ops dispRI:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIEncoding";
let DecoderMethod = "decodeMemRIOperands";
let OperandType = "OPERAND_MEMORY";
}
def memrr : Operand<iPTR> {
let PrintMethod = "printMemRegReg";
let MIOperandInfo = (ops ptr_rc_nor0:$ptrreg, ptr_rc_idx:$offreg);
let OperandType = "OPERAND_MEMORY";
}
def memrix : Operand<iPTR> { // memri where the imm is 4-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispRIX:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIXEncoding";
let DecoderMethod = "decodeMemRIXOperands";
let OperandType = "OPERAND_MEMORY";
}
def memrix16 : Operand<iPTR> { // memri, imm is 16-aligned, 12-bit, Inst{16:27}
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIX16Encoding";
let DecoderMethod = "decodeMemRIX16Operands";
let OperandType = "OPERAND_MEMORY";
}
def spe8dis : Operand<iPTR> { // SPE displacement where the imm is 8-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE8:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE8DisEncoding";
let DecoderMethod = "decodeSPE8Operands";
let OperandType = "OPERAND_MEMORY";
}
def spe4dis : Operand<iPTR> { // SPE displacement where the imm is 4-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE4:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE4DisEncoding";
let DecoderMethod = "decodeSPE4Operands";
let OperandType = "OPERAND_MEMORY";
}
def spe2dis : Operand<iPTR> { // SPE displacement where the imm is 2-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE2:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE2DisEncoding";
let DecoderMethod = "decodeSPE2Operands";
let OperandType = "OPERAND_MEMORY";
}

// A single-register address. This is used with the SjLj
// pseudo-instructions which translates to LD/LWZ. These instructions requires
// G8RC_NOX0 registers.
def memr : Operand<iPTR> {
let MIOperandInfo = (ops ptr_rc_nor0:$ptrreg);
let OperandType = "OPERAND_MEMORY";
}
def PPCTLSRegOperand : AsmOperandClass {
let Name = "TLSReg"; let PredicateMethod = "isTLSReg";
Expand Down
69 changes: 68 additions & 1 deletion llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
Expand Up @@ -13,6 +13,14 @@
namespace llvm {
namespace exegesis {

// Helper to fill a memory operand with a value.
static void setMemOp(InstructionTemplate &IT, int OpIdx,
const MCOperand &OpVal) {
const auto Op = IT.getInstr().Operands[OpIdx];
assert(Op.isExplicit() && "invalid memory pattern");
IT.getValueFor(Op) = OpVal;
}

#include "PPCGenExegesis.inc"

namespace {
Expand All @@ -26,6 +34,9 @@ class ExegesisPowerPCTarget : public ExegesisTarget {
bool matchesArch(Triple::ArchType Arch) const override {
return Arch == Triple::ppc64le;
}
unsigned getScratchMemoryRegister(const Triple &) const override;
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
unsigned Offset) const override;
};
} // end anonymous namespace

Expand All @@ -44,19 +55,75 @@ static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
const APInt &Value) {
if (Value.getBitWidth() > RegBitWidth)
llvm_unreachable("Value must fit in the Register");
// We don't really care the value in reg, ignore the 16 bit
// restriction for now.
// TODO: make sure we get the exact value in reg if needed.
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
.addReg(Reg)
.addImm(Value.getZExtValue());
}

unsigned
ExegesisPowerPCTarget::getScratchMemoryRegister(const Triple &TT) const {
// R13 is reserved as Thread Pointer, we won't use threading in benchmark, so
// use it as scratch memory register
return TT.isArch64Bit() ? PPC::X13 : PPC::R13;
}

void ExegesisPowerPCTarget::fillMemoryOperands(InstructionTemplate &IT,
unsigned Reg,
unsigned Offset) const {
int MemOpIdx = 0;
if (IT.getInstr().hasTiedRegisters())
MemOpIdx = 1;
int DispOpIdx = MemOpIdx + 1;
const auto DispOp = IT.getInstr().Operands[DispOpIdx];
if (DispOp.isReg())
// We don't really care about the real address in snippets,
// So hardcode X1 for X-form Memory Operations for simplicity.
// TODO: materialize the offset into a reggister
setMemOp(IT, DispOpIdx, MCOperand::createReg(PPC::X1));
else
setMemOp(IT, DispOpIdx, MCOperand::createImm(Offset)); // Disp
setMemOp(IT, MemOpIdx + 2, MCOperand::createReg(Reg)); // BaseReg
}

std::vector<MCInst> ExegesisPowerPCTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
// X11 is optional use in function linkage, should be the least used one
// Use it as scratch reg to load immediate.
unsigned ScratchImmReg = PPC::X11;

if (PPC::GPRCRegClass.contains(Reg))
return {loadImmediate(Reg, 32, Value)};
if (PPC::G8RCRegClass.contains(Reg))
return {loadImmediate(Reg, 64, Value)};
errs() << "setRegTo is not implemented, results will be unreliable\n";
if (PPC::F4RCRegClass.contains(Reg))
return {loadImmediate(ScratchImmReg, 64, Value),
MCInstBuilder(PPC::MTVSRD).addReg(Reg).addReg(ScratchImmReg)};
// We don't care the real value in reg, so set 64 bits or duplicate 64 bits
// for simplicity.
// TODO: update these if we need a accurate 128 values in registers.
if (PPC::VRRCRegClass.contains(Reg))
return {loadImmediate(ScratchImmReg, 64, Value),
MCInstBuilder(PPC::MTVRD).addReg(Reg).addReg(ScratchImmReg)};
if (PPC::VSRCRegClass.contains(Reg))
return {loadImmediate(ScratchImmReg, 64, Value),
MCInstBuilder(PPC::MTVSRDD)
.addReg(Reg)
.addReg(ScratchImmReg)
.addReg(ScratchImmReg)};
if (PPC::VFRCRegClass.contains(Reg))
return {loadImmediate(ScratchImmReg, 64, Value),
MCInstBuilder(PPC::MTVSRD).addReg(Reg).addReg(ScratchImmReg)};
// SPE not supported yet
if (PPC::SPERCRegClass.contains(Reg)) {
errs() << "Unsupported SPE Reg:" << Reg << "\n";
return {};
}
errs() << "setRegTo is not implemented, results will be unreliable:" << Reg
<< "\n";
return {};
}

Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/tools/llvm-exegesis/PowerPC/CMakeLists.txt
Expand Up @@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS

add_llvm_target_unittest(LLVMExegesisPowerPCTests
AnalysisTest.cpp
SnippetGeneratorTest.cpp
TargetTest.cpp
)
target_link_libraries(LLVMExegesisPowerPCTests PRIVATE
Expand Down

0 comments on commit c8ec685

Please sign in to comment.