mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
[llvm-exegesis][PowerPC] Add more register classes
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
This commit is contained in:
parent
65bd36f2bc
commit
a97bf3c2f2
@ -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
|
||||
@ -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);
|
||||
|
@ -666,6 +666,7 @@ def PPCU1ImmAsmOperand : AsmOperandClass {
|
||||
def u1imm : Operand<i32> {
|
||||
let PrintMethod = "printU1ImmOperand";
|
||||
let ParserMatchClass = PPCU1ImmAsmOperand;
|
||||
let OperandType = "OPERAND_IMMEDIATE";
|
||||
}
|
||||
|
||||
def PPCU2ImmAsmOperand : AsmOperandClass {
|
||||
@ -675,6 +676,7 @@ def PPCU2ImmAsmOperand : AsmOperandClass {
|
||||
def u2imm : Operand<i32> {
|
||||
let PrintMethod = "printU2ImmOperand";
|
||||
let ParserMatchClass = PPCU2ImmAsmOperand;
|
||||
let OperandType = "OPERAND_IMMEDIATE";
|
||||
}
|
||||
|
||||
def PPCATBitsAsHintAsmOperand : AsmOperandClass {
|
||||
@ -684,6 +686,7 @@ def PPCATBitsAsHintAsmOperand : AsmOperandClass {
|
||||
def atimm : Operand<i32> {
|
||||
let PrintMethod = "printATBitsAsHint";
|
||||
let ParserMatchClass = PPCATBitsAsHintAsmOperand;
|
||||
let OperandType = "OPERAND_IMMEDIATE";
|
||||
}
|
||||
|
||||
def PPCU3ImmAsmOperand : AsmOperandClass {
|
||||
@ -693,6 +696,7 @@ def PPCU3ImmAsmOperand : AsmOperandClass {
|
||||
def u3imm : Operand<i32> {
|
||||
let PrintMethod = "printU3ImmOperand";
|
||||
let ParserMatchClass = PPCU3ImmAsmOperand;
|
||||
let OperandType = "OPERAND_IMMEDIATE";
|
||||
}
|
||||
|
||||
def PPCU4ImmAsmOperand : AsmOperandClass {
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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";
|
||||
@ -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); }]>;
|
||||
@ -970,40 +988,47 @@ 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
|
||||
@ -1011,6 +1036,7 @@ def spe2dis : Operand<iPTR> { // SPE displacement where the imm is 2-aligned.
|
||||
// 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";
|
||||
|
@ -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 {
|
||||
@ -26,6 +34,9 @@ private:
|
||||
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
|
||||
|
||||
@ -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 {};
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS
|
||||
|
||||
add_llvm_target_unittest(LLVMExegesisPowerPCTests
|
||||
AnalysisTest.cpp
|
||||
SnippetGeneratorTest.cpp
|
||||
TargetTest.cpp
|
||||
)
|
||||
target_link_libraries(LLVMExegesisPowerPCTests PRIVATE
|
||||
|
136
unittests/tools/llvm-exegesis/PowerPC/SnippetGeneratorTest.cpp
Normal file
136
unittests/tools/llvm-exegesis/PowerPC/SnippetGeneratorTest.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
//===-- SnippetGeneratorTest.cpp --------------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "../Common/AssemblerUtils.h"
|
||||
#include "LlvmState.h"
|
||||
#include "MCInstrDescView.h"
|
||||
#include "PPCInstrInfo.h"
|
||||
#include "ParallelSnippetGenerator.h"
|
||||
#include "RegisterAliasing.h"
|
||||
#include "SerialSnippetGenerator.h"
|
||||
#include "TestBase.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
namespace {
|
||||
|
||||
using testing::AnyOf;
|
||||
using testing::ElementsAre;
|
||||
using testing::HasSubstr;
|
||||
using testing::SizeIs;
|
||||
|
||||
MATCHER(IsInvalid, "") { return !arg.isValid(); }
|
||||
MATCHER(IsReg, "") { return arg.isReg(); }
|
||||
|
||||
class PPCSnippetGeneratorTest : public PPCTestBase {};
|
||||
|
||||
template <typename SnippetGeneratorT>
|
||||
class SnippetGeneratorTest : public PPCSnippetGeneratorTest {
|
||||
protected:
|
||||
SnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()) {}
|
||||
|
||||
std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
|
||||
randomGenerator().seed(0); // Initialize seed.
|
||||
const Instruction &Instr = State.getIC().getInstr(Opcode);
|
||||
auto CodeTemplateOrError = Generator.generateCodeTemplates(
|
||||
&Instr, State.getRATC().emptyRegisters());
|
||||
EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
|
||||
return std::move(CodeTemplateOrError.get());
|
||||
}
|
||||
|
||||
SnippetGeneratorT Generator;
|
||||
};
|
||||
|
||||
using SerialSnippetGeneratorTest = SnippetGeneratorTest<SerialSnippetGenerator>;
|
||||
|
||||
using ParallelSnippetGeneratorTest =
|
||||
SnippetGeneratorTest<ParallelSnippetGenerator>;
|
||||
|
||||
TEST_F(SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
|
||||
// - ADD8
|
||||
// - Op0 Explicit Def RegClass(G8RC)
|
||||
// - Op1 Explicit Use RegClass(G8RC)
|
||||
// - Op2 Explicit Use RegClass(G8RC)
|
||||
// - Var0 [Op0]
|
||||
// - Var1 [Op1]
|
||||
// - Var2 [Op2]
|
||||
// - hasAliasingRegisters
|
||||
const unsigned Opcode = PPC::ADD8;
|
||||
const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
|
||||
ASSERT_THAT(CodeTemplates, SizeIs(1));
|
||||
const auto &CT = CodeTemplates[0];
|
||||
EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
|
||||
EXPECT_THAT(IT.getVariableValues(),
|
||||
AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
|
||||
ElementsAre(IsReg(), IsReg(), IsInvalid())))
|
||||
<< "Op0 is either set to Op1 or to Op2";
|
||||
}
|
||||
|
||||
TEST_F(SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
|
||||
|
||||
// - RLDIMI
|
||||
// - Op0 Explicit Def RegClass(G8RC)
|
||||
// - Op1 Explicit Use RegClass(G8RC) TiedToOp0
|
||||
// - Op2 Explicit Use RegClass(G8RC)
|
||||
// - Op3 Explicit Use Immediate
|
||||
// - Op4 Explicit Use Immediate
|
||||
// - Var0 [Op0,Op1]
|
||||
// - Var1 [Op2]
|
||||
// - Var2 [Op3]
|
||||
// - Var3 [Op4]
|
||||
// - hasTiedRegisters (execution is always serial)
|
||||
// - hasAliasingRegisters
|
||||
// - RLDIMI
|
||||
const unsigned Opcode = PPC::RLDIMI;
|
||||
const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
|
||||
ASSERT_THAT(CodeTemplates, SizeIs(1));
|
||||
const auto &CT = CodeTemplates[0];
|
||||
EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS);
|
||||
ASSERT_THAT(CT.Instructions, SizeIs(1));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(4));
|
||||
EXPECT_THAT(IT.getVariableValues()[2], IsInvalid()) << "Operand 1 is not set";
|
||||
EXPECT_THAT(IT.getVariableValues()[3], IsInvalid()) << "Operand 2 is not set";
|
||||
}
|
||||
|
||||
TEST_F(ParallelSnippetGeneratorTest, MemoryUse) {
|
||||
// - LDX
|
||||
// - Op0 Explicit Def RegClass(G8RC)
|
||||
// - Op1 Explicit Use Memory RegClass(GPRC)
|
||||
// - Op2 Explicit Use Memory RegClass(VSSRC)
|
||||
// - Var0 [Op0]
|
||||
// - Var1 [Op1]
|
||||
// - Var2 [Op2]
|
||||
// - hasMemoryOperands
|
||||
// - hasAliasingRegisters
|
||||
const unsigned Opcode = PPC::LDX;
|
||||
const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
|
||||
ASSERT_THAT(CodeTemplates, SizeIs(1));
|
||||
const auto &CT = CodeTemplates[0];
|
||||
EXPECT_THAT(CT.Info, HasSubstr("instruction has no tied variables picking "
|
||||
"Uses different from defs"));
|
||||
EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
|
||||
ASSERT_THAT(CT.Instructions,
|
||||
SizeIs(ParallelSnippetGenerator::kMinNumDifferentAddresses));
|
||||
const InstructionTemplate &IT = CT.Instructions[0];
|
||||
EXPECT_THAT(IT.getOpcode(), Opcode);
|
||||
ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
|
||||
EXPECT_EQ(IT.getVariableValues()[1].getReg(), PPC::X1);
|
||||
EXPECT_EQ(IT.getVariableValues()[2].getReg(), PPC::X13);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace exegesis
|
||||
} // namespace llvm
|
42
unittests/tools/llvm-exegesis/PowerPC/TestBase.h
Normal file
42
unittests/tools/llvm-exegesis/PowerPC/TestBase.h
Normal file
@ -0,0 +1,42 @@
|
||||
//===-- TestBase.h ----------------------------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test fixture common to all PowerPC tests.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_POWERPC_TESTBASE_H
|
||||
#define LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_POWERPC_TESTBASE_H
|
||||
|
||||
#include "LlvmState.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
void InitializePowerPCExegesisTarget();
|
||||
|
||||
class PPCTestBase : public ::testing::Test {
|
||||
protected:
|
||||
PPCTestBase() : State("powerpc64le-unknown-linux", "ppc64le") {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
LLVMInitializePowerPCTargetInfo();
|
||||
LLVMInitializePowerPCTargetMC();
|
||||
LLVMInitializePowerPCTarget();
|
||||
InitializePowerPCExegesisTarget();
|
||||
}
|
||||
|
||||
const LLVMState State;
|
||||
};
|
||||
|
||||
} // namespace exegesis
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user