Skip to content

Commit f7d7847

Browse files
authored
[LoongArch][MC] Refine MCInstrAnalysis based on registers used (#71276)
MCInstrAnalysis can return properties of instructions (e.g., isCall(), isBranch(),...) based on the informations that MCInstrDesc can get from *InstrInfo*.td files. These infos are based on opcodes only, but JIRL can have different properties based on different registers used. So this patch refines several MCInstrAnalysis methods: isTerminator, isCall,isReturn,isBranch,isUnconditionalBranch and isIndirectBranch. This patch also allows BOLT which will be supported on LoongArch later to get right instruction infos.
1 parent fe8c649 commit f7d7847

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,82 @@ class LoongArchMCInstrAnalysis : public MCInstrAnalysis {
104104

105105
return false;
106106
}
107+
108+
bool isTerminator(const MCInst &Inst) const override {
109+
if (MCInstrAnalysis::isTerminator(Inst))
110+
return true;
111+
112+
switch (Inst.getOpcode()) {
113+
default:
114+
return false;
115+
case LoongArch::JIRL:
116+
return Inst.getOperand(0).getReg() == LoongArch::R0;
117+
}
118+
}
119+
120+
bool isCall(const MCInst &Inst) const override {
121+
if (MCInstrAnalysis::isCall(Inst))
122+
return true;
123+
124+
switch (Inst.getOpcode()) {
125+
default:
126+
return false;
127+
case LoongArch::JIRL:
128+
return Inst.getOperand(0).getReg() != LoongArch::R0;
129+
}
130+
}
131+
132+
bool isReturn(const MCInst &Inst) const override {
133+
if (MCInstrAnalysis::isReturn(Inst))
134+
return true;
135+
136+
switch (Inst.getOpcode()) {
137+
default:
138+
return false;
139+
case LoongArch::JIRL:
140+
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
141+
Inst.getOperand(1).getReg() == LoongArch::R1;
142+
}
143+
}
144+
145+
bool isBranch(const MCInst &Inst) const override {
146+
if (MCInstrAnalysis::isBranch(Inst))
147+
return true;
148+
149+
switch (Inst.getOpcode()) {
150+
default:
151+
return false;
152+
case LoongArch::JIRL:
153+
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
154+
Inst.getOperand(1).getReg() != LoongArch::R1;
155+
}
156+
}
157+
158+
bool isUnconditionalBranch(const MCInst &Inst) const override {
159+
if (MCInstrAnalysis::isUnconditionalBranch(Inst))
160+
return true;
161+
162+
switch (Inst.getOpcode()) {
163+
default:
164+
return false;
165+
case LoongArch::JIRL:
166+
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
167+
Inst.getOperand(1).getReg() != LoongArch::R1;
168+
}
169+
}
170+
171+
bool isIndirectBranch(const MCInst &Inst) const override {
172+
if (MCInstrAnalysis::isIndirectBranch(Inst))
173+
return true;
174+
175+
switch (Inst.getOpcode()) {
176+
default:
177+
return false;
178+
case LoongArch::JIRL:
179+
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
180+
Inst.getOperand(1).getReg() != LoongArch::R1;
181+
}
182+
}
107183
};
108184

109185
} // end namespace

llvm/unittests/Target/LoongArch/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(LLVM_LINK_COMPONENTS
2020

2121
add_llvm_target_unittest(LoongArchTests
2222
InstSizes.cpp
23+
MCInstrAnalysisTest.cpp
2324
)
2425

2526
set_property(TARGET LoongArchTests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===- MCInstrAnalysisTest.cpp - LoongArchMCInstrAnalysis 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 "llvm/MC/MCInstrAnalysis.h"
10+
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
11+
#include "llvm/MC/MCInstBuilder.h"
12+
#include "llvm/MC/TargetRegistry.h"
13+
#include "llvm/Support/TargetSelect.h"
14+
15+
#include "gtest/gtest.h"
16+
17+
#include <memory>
18+
19+
using namespace llvm;
20+
21+
namespace {
22+
23+
class InstrAnalysisTest : public testing::TestWithParam<const char *> {
24+
protected:
25+
std::unique_ptr<const MCInstrInfo> Info;
26+
std::unique_ptr<const MCInstrAnalysis> Analysis;
27+
28+
static void SetUpTestSuite() {
29+
LLVMInitializeLoongArchTargetInfo();
30+
LLVMInitializeLoongArchTarget();
31+
LLVMInitializeLoongArchTargetMC();
32+
}
33+
34+
InstrAnalysisTest() {
35+
std::string Error;
36+
const Target *TheTarget =
37+
TargetRegistry::lookupTarget(Triple::normalize(GetParam()), Error);
38+
Info = std::unique_ptr<const MCInstrInfo>(TheTarget->createMCInstrInfo());
39+
Analysis = std::unique_ptr<const MCInstrAnalysis>(
40+
TheTarget->createMCInstrAnalysis(Info.get()));
41+
}
42+
};
43+
44+
} // namespace
45+
46+
static MCInst beq() {
47+
return MCInstBuilder(LoongArch::BEQ)
48+
.addReg(LoongArch::R0)
49+
.addReg(LoongArch::R1)
50+
.addImm(32);
51+
}
52+
53+
static MCInst bl() { return MCInstBuilder(LoongArch::BL).addImm(32); }
54+
55+
static MCInst jirl(unsigned RD, unsigned RJ = LoongArch::R10) {
56+
return MCInstBuilder(LoongArch::JIRL).addReg(RD).addReg(RJ).addImm(16);
57+
}
58+
59+
TEST_P(InstrAnalysisTest, IsTerminator) {
60+
EXPECT_TRUE(Analysis->isTerminator(beq()));
61+
EXPECT_FALSE(Analysis->isTerminator(bl()));
62+
EXPECT_TRUE(Analysis->isTerminator(jirl(LoongArch::R0)));
63+
EXPECT_FALSE(Analysis->isTerminator(jirl(LoongArch::R5)));
64+
}
65+
66+
TEST_P(InstrAnalysisTest, IsCall) {
67+
EXPECT_FALSE(Analysis->isCall(beq()));
68+
EXPECT_TRUE(Analysis->isCall(bl()));
69+
EXPECT_TRUE(Analysis->isCall(jirl(LoongArch::R1)));
70+
EXPECT_FALSE(Analysis->isCall(jirl(LoongArch::R0)));
71+
}
72+
73+
TEST_P(InstrAnalysisTest, IsReturn) {
74+
EXPECT_FALSE(Analysis->isReturn(beq()));
75+
EXPECT_FALSE(Analysis->isReturn(bl()));
76+
EXPECT_TRUE(Analysis->isReturn(jirl(LoongArch::R0, LoongArch::R1)));
77+
EXPECT_FALSE(Analysis->isReturn(jirl(LoongArch::R0)));
78+
EXPECT_FALSE(Analysis->isReturn(jirl(LoongArch::R1)));
79+
}
80+
81+
TEST_P(InstrAnalysisTest, IsBranch) {
82+
EXPECT_TRUE(Analysis->isBranch(beq()));
83+
EXPECT_FALSE(Analysis->isBranch(bl()));
84+
EXPECT_TRUE(Analysis->isBranch(jirl(LoongArch::R0)));
85+
EXPECT_FALSE(Analysis->isBranch(jirl(LoongArch::R1)));
86+
EXPECT_FALSE(Analysis->isBranch(jirl(LoongArch::R0, LoongArch::R1)));
87+
}
88+
89+
TEST_P(InstrAnalysisTest, IsUnconditionalBranch) {
90+
EXPECT_FALSE(Analysis->isUnconditionalBranch(beq()));
91+
EXPECT_FALSE(Analysis->isUnconditionalBranch(bl()));
92+
EXPECT_TRUE(Analysis->isUnconditionalBranch(jirl(LoongArch::R0)));
93+
EXPECT_FALSE(Analysis->isUnconditionalBranch(jirl(LoongArch::R1)));
94+
EXPECT_FALSE(
95+
Analysis->isUnconditionalBranch(jirl(LoongArch::R0, LoongArch::R1)));
96+
}
97+
98+
TEST_P(InstrAnalysisTest, IsIndirectBranch) {
99+
EXPECT_FALSE(Analysis->isIndirectBranch(beq()));
100+
EXPECT_FALSE(Analysis->isIndirectBranch(bl()));
101+
EXPECT_TRUE(Analysis->isIndirectBranch(jirl(LoongArch::R0)));
102+
EXPECT_FALSE(Analysis->isIndirectBranch(jirl(LoongArch::R1)));
103+
EXPECT_FALSE(Analysis->isIndirectBranch(jirl(LoongArch::R0, LoongArch::R1)));
104+
}
105+
106+
INSTANTIATE_TEST_SUITE_P(LA32And64, InstrAnalysisTest,
107+
testing::Values("loongarch32", "loongarch64"));

0 commit comments

Comments
 (0)