diff --git a/llvm/test/tools/llvm-exegesis/Mips/latency-GPR64.s b/llvm/test/tools/llvm-exegesis/Mips/latency-GPR64.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-exegesis/Mips/latency-GPR64.s @@ -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: ... diff --git a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp @@ -30,26 +30,75 @@ }; } // 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 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 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 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 {}; } diff --git a/llvm/unittests/tools/llvm-exegesis/Mips/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/Mips/TargetTest.cpp --- a/llvm/unittests/tools/llvm-exegesis/Mips/TargetTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/Mips/TargetTest.cpp @@ -44,9 +44,22 @@ return Property(&MCInst::getOpcode, Eq(Opcode)); } -Matcher IsLoadLowImm(int64_t Reg, int64_t Value) { - return AllOf(OpcodeIs(Mips::ORi), - ElementsAre(IsReg(Reg), IsReg(Mips::ZERO), IsImm(Value))); +Matcher 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 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 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 @@ 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) {