1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[llvm-exegesis][mips] Expand loadImmediate()

Add support for loading 32-bit immediates and enable the use of GPR64
registers.

Differential Revision: https://reviews.llvm.org/D71873
This commit is contained in:
Miloš Stojanović 2019-12-25 11:23:01 +01:00
parent 5554f90776
commit 7696c3e850
3 changed files with 133 additions and 18 deletions

View File

@ -0,0 +1,11 @@
# RUN: llvm-exegesis -mode=latency -opcode-name=AND64 | FileCheck %s
CHECK: ---
CHECK-NEXT: mode: latency
CHECK-NEXT: key:
CHECK-NEXT: instructions:
CHECK-NEXT: AND64
CHECK-NEXT: config: ''
CHECK-NEXT: register_initial_values:
CHECK-DAG: - '[[REG1:[A-Z0-9]+_64]]=0x0'
CHECK-LAST: ...

View File

@ -30,26 +30,75 @@ private:
};
} // end anonymous namespace
// Generates instruction to load an immediate value into a register.
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
const APInt &Value) {
if (Value.getActiveBits() > 16)
llvm_unreachable("Not implemented for Values wider than 16 bits");
if (Value.getBitWidth() > RegBitWidth)
llvm_unreachable("Value must fit in the Register");
return MCInstBuilder(Mips::ORi)
.addReg(Reg)
.addReg(Mips::ZERO)
.addImm(Value.getZExtValue());
// Generates instructions to load an immediate value into a register.
static std::vector<MCInst> loadImmediate(unsigned Reg, bool IsGPR32,
const APInt &Value) {
unsigned ZeroReg;
unsigned ORi, LUi, SLL;
if (IsGPR32) {
ZeroReg = Mips::ZERO;
ORi = Mips::ORi;
SLL = Mips::SLL;
LUi = Mips::LUi;
} else {
ZeroReg = Mips::ZERO_64;
ORi = Mips::ORi64;
SLL = Mips::SLL64_64;
LUi = Mips::LUi64;
}
if (Value.isIntN(16)) {
return {MCInstBuilder(ORi)
.addReg(Reg)
.addReg(ZeroReg)
.addImm(Value.getZExtValue())};
}
std::vector<MCInst> Instructions;
if (Value.isIntN(32)) {
const uint16_t HiBits = Value.getHiBits(16).getZExtValue();
if (!IsGPR32 && Value.getActiveBits() == 32) {
// Expand to an ORi instead of a LUi to avoid sign-extending into the
// upper 32 bits.
Instructions.push_back(
MCInstBuilder(ORi)
.addReg(Reg)
.addReg(ZeroReg)
.addImm(HiBits));
Instructions.push_back(
MCInstBuilder(SLL)
.addReg(Reg)
.addReg(Reg)
.addImm(16));
} else {
Instructions.push_back(
MCInstBuilder(LUi)
.addReg(Reg)
.addImm(HiBits));
}
const uint16_t LoBits = Value.getLoBits(16).getZExtValue();
if (LoBits) {
Instructions.push_back(
MCInstBuilder(ORi)
.addReg(Reg)
.addReg(ZeroReg)
.addImm(LoBits));
}
return std::move(Instructions);
}
llvm_unreachable("Not implemented for values wider than 32 bits");
}
std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
if (Mips::GPR32RegClass.contains(Reg))
return {loadImmediate(Reg, 32, Value)};
return loadImmediate(Reg, true, Value);
if (Mips::GPR64RegClass.contains(Reg))
return {loadImmediate(Reg, 64, Value)};
return loadImmediate(Reg, false, Value);
errs() << "setRegTo is not implemented, results will be unreliable\n";
return {};
}

View File

@ -44,9 +44,22 @@ Matcher<MCInst> OpcodeIs(unsigned Opcode) {
return Property(&MCInst::getOpcode, Eq(Opcode));
}
Matcher<MCInst> IsLoadLowImm(int64_t Reg, int64_t Value) {
return AllOf(OpcodeIs(Mips::ORi),
ElementsAre(IsReg(Reg), IsReg(Mips::ZERO), IsImm(Value)));
Matcher<MCInst> IsLoadLow16BitImm(unsigned Reg, int64_t Value, bool IsGPR32) {
const unsigned ZeroReg = IsGPR32 ? Mips::ZERO : Mips::ZERO_64;
const unsigned ORi = IsGPR32 ? Mips::ORi : Mips::ORi64;
return AllOf(OpcodeIs(ORi),
ElementsAre(IsReg(Reg), IsReg(ZeroReg), IsImm(Value)));
}
Matcher<MCInst> IsLoadHigh16BitImm(unsigned Reg, int64_t Value, bool IsGPR32) {
const unsigned LUi = IsGPR32 ? Mips::LUi : Mips::LUi64;
return AllOf(OpcodeIs(LUi), ElementsAre(IsReg(Reg), IsImm(Value)));
}
Matcher<MCInst> IsShift(unsigned Reg, uint16_t Amount, bool IsGPR32) {
const unsigned SLL = IsGPR32 ? Mips::SLL : Mips::SLL64_64;
return AllOf(OpcodeIs(SLL),
ElementsAre(IsReg(Reg), IsReg(Reg), IsImm(Amount)));
}
constexpr const char kTriple[] = "mips-unknown-linux";
@ -70,11 +83,53 @@ protected:
LLVMState State;
};
TEST_F(MipsTargetTest, SetRegToConstant) {
TEST_F(MipsTargetTest, SetGPR32RegTo16BitValue) {
const uint16_t Value = 0xFFFFU;
const unsigned Reg = Mips::T0;
EXPECT_THAT(setRegTo(Reg, APInt(16, Value)),
ElementsAre(IsLoadLowImm(Reg, Value)));
ElementsAre(IsLoadLow16BitImm(Reg, Value, true)));
}
TEST_F(MipsTargetTest, SetGPR64RegTo16BitValue) {
const uint16_t Value = 0xFFFFU;
const unsigned Reg = Mips::T0_64;
EXPECT_THAT(setRegTo(Reg, APInt(16, Value)),
ElementsAre(IsLoadLow16BitImm(Reg, Value, false)));
}
TEST_F(MipsTargetTest, SetGPR32RegTo32BitValue) {
const uint32_t Value0 = 0xFFFF0000UL;
const unsigned Reg0 = Mips::T0;
EXPECT_THAT(setRegTo(Reg0, APInt(32, Value0)),
ElementsAre(IsLoadHigh16BitImm(Reg0, 0xFFFFU, true)));
const uint32_t Value1 = 0xFFFFFFFFUL;
const unsigned Reg1 = Mips::T1;
EXPECT_THAT(setRegTo(Reg1, APInt(32, Value1)),
ElementsAre(IsLoadHigh16BitImm(Reg1, 0xFFFFU, true),
IsLoadLow16BitImm(Reg1, 0xFFFFU, true)));
}
TEST_F(MipsTargetTest, SetGPR64RegTo32BitValue) {
const uint32_t Value0 = 0x7FFF0000UL;
const unsigned Reg0 = Mips::T0_64;
EXPECT_THAT(setRegTo(Reg0, APInt(32, Value0)),
ElementsAre(IsLoadHigh16BitImm(Reg0, 0x7FFFU, false)));
const uint32_t Value1 = 0x7FFFFFFFUL;
const unsigned Reg1 = Mips::T1_64;
EXPECT_THAT(setRegTo(Reg1, APInt(32, Value1)),
ElementsAre(IsLoadHigh16BitImm(Reg1, 0x7FFFU, false),
IsLoadLow16BitImm(Reg1, 0xFFFFU, false)));
const uint32_t Value2 = 0xFFFF0000UL;
const unsigned Reg2 = Mips::T2_64;
EXPECT_THAT(setRegTo(Reg2, APInt(32, Value2)),
ElementsAre(IsLoadLow16BitImm(Reg2, 0xFFFFU, false),
IsShift(Reg2, 16, false)));
const uint32_t Value3 = 0xFFFFFFFFUL;
const unsigned Reg3 = Mips::T3_64;
EXPECT_THAT(setRegTo(Reg3, APInt(32, Value3)),
ElementsAre(IsLoadLow16BitImm(Reg3, 0xFFFFU, false),
IsShift(Reg3, 16, false),
IsLoadLow16BitImm(Reg3, 0xFFFFU, false)));
}
TEST_F(MipsTargetTest, DefaultPfmCounters) {