Skip to content

Commit 4ca55a8

Browse files
asbsr-tream
authored andcommitted
[RISCV] Implement RISCVInstrInfo::isAddImmediate (llvm#72356)
This hook is called by the target-independent implementation of TargetInstrInfo::describeLoadedValue. I've opted to test it via a C++ unit test, which although fiddly to set up seems the right way to test a function with such clear intended semantics (rather than testing the impact indirectly). isAddImmediate will never recognise ADDIW as an add immediate which I _think_ is conservatively correct, as the caller may not understand its semantics vs ADDI. Note that although the doc comment for isAddImmediate specifies its behaviour solely in terms of physical registers, none of the current in-tree implementations (including this one) bail out on virtual registers (see llvm#72357).
1 parent c5b9dc6 commit 4ca55a8

File tree

4 files changed

+121
-1
lines changed

4 files changed

+121
-1
lines changed

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,6 +2441,23 @@ MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall(
24412441
return It;
24422442
}
24432443

2444+
std::optional<RegImmPair> RISCVInstrInfo::isAddImmediate(const MachineInstr &MI,
2445+
Register Reg) const {
2446+
// TODO: Handle cases where Reg is a super- or sub-register of the
2447+
// destination register.
2448+
const MachineOperand &Op0 = MI.getOperand(0);
2449+
if (!Op0.isReg() || Reg != Op0.getReg())
2450+
return std::nullopt;
2451+
2452+
// Don't consider ADDIW as a candidate because the caller may not be aware
2453+
// of its sign extension behaviour.
2454+
if (MI.getOpcode() == RISCV::ADDI && MI.getOperand(1).isReg() &&
2455+
MI.getOperand(2).isImm())
2456+
return RegImmPair{MI.getOperand(1).getReg(), MI.getOperand(2).getImm()};
2457+
2458+
return std::nullopt;
2459+
}
2460+
24442461
// MIR printer helper function to annotate Operands with a comment.
24452462
std::string RISCVInstrInfo::createMIROperandComment(
24462463
const MachineInstr &MI, const MachineOperand &Op, unsigned OpIdx,

llvm/lib/Target/RISCV/RISCVInstrInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
197197
MachineBasicBlock::iterator &It, MachineFunction &MF,
198198
outliner::Candidate &C) const override;
199199

200+
std::optional<RegImmPair> isAddImmediate(const MachineInstr &MI,
201+
Register Reg) const override;
202+
200203
bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1,
201204
unsigned &SrcOpIdx2) const override;
202205
MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI,

llvm/unittests/Target/RISCV/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ set(LLVM_LINK_COMPONENTS
77
RISCVCodeGen
88
RISCVDesc
99
RISCVInfo
10-
TargetParser
10+
CodeGen
11+
Core
1112
MC
13+
SelectionDAG
14+
TargetParser
1215
)
1316

1417
add_llvm_target_unittest(RISCVTests
1518
MCInstrAnalysisTest.cpp
1619
RISCVBaseInfoTest.cpp
20+
RISCVInstrInfoTest.cpp
1721
)
1822

1923
set_property(TARGET RISCVTests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//===- RISCVInstrInfoTest.cpp - RISCVInstrInfo unit tests -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "RISCVInstrInfo.h"
10+
#include "RISCVSubtarget.h"
11+
#include "RISCVTargetMachine.h"
12+
#include "llvm/CodeGen/MachineModuleInfo.h"
13+
#include "llvm/MC/TargetRegistry.h"
14+
#include "llvm/Support/TargetSelect.h"
15+
#include "llvm/Target/TargetMachine.h"
16+
#include "llvm/Target/TargetOptions.h"
17+
18+
#include "gtest/gtest.h"
19+
20+
#include <memory>
21+
22+
using namespace llvm;
23+
24+
namespace {
25+
26+
class RISCVInstrInfoTest : public testing::TestWithParam<const char *> {
27+
protected:
28+
std::unique_ptr<LLVMContext> Ctx;
29+
std::unique_ptr<RISCVSubtarget> ST;
30+
std::unique_ptr<MachineModuleInfo> MMI;
31+
std::unique_ptr<MachineFunction> MF;
32+
33+
static void SetUpTestSuite() {
34+
LLVMInitializeRISCVTargetInfo();
35+
LLVMInitializeRISCVTarget();
36+
LLVMInitializeRISCVTargetMC();
37+
}
38+
39+
RISCVInstrInfoTest() {
40+
std::string Error;
41+
auto TT(Triple::normalize(GetParam()));
42+
const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
43+
TargetOptions Options;
44+
45+
RISCVTargetMachine *TM = static_cast<RISCVTargetMachine *>(
46+
TheTarget->createTargetMachine(TT, "generic", "", Options, std::nullopt,
47+
std::nullopt, CodeGenOptLevel::Default));
48+
49+
Ctx = std::make_unique<LLVMContext>();
50+
Module M("Module", *Ctx);
51+
M.setDataLayout(TM->createDataLayout());
52+
auto *FType = FunctionType::get(Type::getVoidTy(*Ctx), false);
53+
auto *F = Function::Create(FType, GlobalValue::ExternalLinkage, "Test", &M);
54+
MMI = std::make_unique<MachineModuleInfo>(TM);
55+
56+
ST = std::make_unique<RISCVSubtarget>(
57+
TM->getTargetTriple(), TM->getTargetCPU(), TM->getTargetCPU(),
58+
TM->getTargetFeatureString(),
59+
TM->getTargetTriple().isArch64Bit() ? "lp64" : "ilp32", 0, 0, *TM);
60+
61+
MF = std::make_unique<MachineFunction>(*F, *TM, *ST, 42, *MMI);
62+
}
63+
};
64+
65+
TEST_P(RISCVInstrInfoTest, IsAddImmediate) {
66+
const RISCVInstrInfo *TII = ST->getInstrInfo();
67+
DebugLoc DL;
68+
69+
MachineInstr *MI1 = BuildMI(*MF, DL, TII->get(RISCV::ADDI), RISCV::X1)
70+
.addReg(RISCV::X2)
71+
.addImm(-128)
72+
.getInstr();
73+
auto MI1Res = TII->isAddImmediate(*MI1, RISCV::X1);
74+
ASSERT_TRUE(MI1Res.has_value());
75+
EXPECT_EQ(MI1Res->Reg, RISCV::X2);
76+
EXPECT_EQ(MI1Res->Imm, -128);
77+
EXPECT_FALSE(TII->isAddImmediate(*MI1, RISCV::X2).has_value());
78+
79+
MachineInstr *MI2 =
80+
BuildMI(*MF, DL, TII->get(RISCV::LUI), RISCV::X1).addImm(-128).getInstr();
81+
EXPECT_FALSE(TII->isAddImmediate(*MI2, RISCV::X1));
82+
83+
// Check ADDIW isn't treated as isAddImmediate.
84+
if (ST->is64Bit()) {
85+
MachineInstr *MI3 = BuildMI(*MF, DL, TII->get(RISCV::ADDIW), RISCV::X1)
86+
.addReg(RISCV::X2)
87+
.addImm(-128)
88+
.getInstr();
89+
EXPECT_FALSE(TII->isAddImmediate(*MI3, RISCV::X1));
90+
}
91+
}
92+
93+
} // namespace
94+
95+
INSTANTIATE_TEST_SUITE_P(RV32And64, RISCVInstrInfoTest,
96+
testing::Values("riscv32", "riscv64"));

0 commit comments

Comments
 (0)