Skip to content

Commit 2b9d089

Browse files
committed
[RISCV][MC] Implement evaluateBranch for auipc+jalr pairs
This patch implements `MCInstrAnalysis` state in order to be able analyze auipc+jalr pairs inside `evaluateBranch`. This is implemented as follows: - State: array of currently known GPR values; - Whenever an auipc is detected in `updateState`, update the state value of RD with the immediate; - Whenever a jalr is detected in `evaluateBranch`, check if the state holds a value for RS1 and use that to compute its target. Note that this is similar to how binutils implements it and the output of llvm-objdump should now mostly match the one of GNU objdump. This patch also updates the relevant llvm-objdump patches and adds a new one testing the output for interleaved auipc+jalr pairs.
1 parent 7228670 commit 2b9d089

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,40 @@ static MCTargetStreamer *createRISCVNullTargetStreamer(MCStreamer &S) {
114114
namespace {
115115

116116
class RISCVMCInstrAnalysis : public MCInstrAnalysis {
117+
std::optional<int64_t> GPRState[31];
118+
119+
void setGPRState(unsigned Reg, int64_t Value) {
120+
assert(Reg >= RISCV::X0 && Reg <= RISCV::X31 && "Invalid GPR reg");
121+
122+
if (Reg != RISCV::X0)
123+
GPRState[Reg - RISCV::X1] = Value;
124+
}
125+
126+
std::optional<int64_t> getGPRState(unsigned Reg) const {
127+
assert(Reg >= RISCV::X0 && Reg <= RISCV::X31 && "Invalid GPR reg");
128+
129+
if (Reg == RISCV::X0)
130+
return 0;
131+
return GPRState[Reg - RISCV::X1];
132+
}
133+
117134
public:
118135
explicit RISCVMCInstrAnalysis(const MCInstrInfo *Info)
119136
: MCInstrAnalysis(Info) {}
120137

138+
void resetState() override {
139+
std::fill(std::begin(GPRState), std::end(GPRState), std::nullopt);
140+
}
141+
142+
void updateState(const MCInst &Inst, uint64_t Addr) override {
143+
switch (Inst.getOpcode()) {
144+
case RISCV::AUIPC:
145+
setGPRState(Inst.getOperand(0).getReg(),
146+
Addr + (Inst.getOperand(1).getImm() << 12));
147+
break;
148+
}
149+
}
150+
121151
bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size,
122152
uint64_t &Target) const override {
123153
if (isConditionalBranch(Inst)) {
@@ -140,6 +170,15 @@ class RISCVMCInstrAnalysis : public MCInstrAnalysis {
140170
return true;
141171
}
142172

173+
if (Inst.getOpcode() == RISCV::JALR) {
174+
if (auto TargetRegState = getGPRState(Inst.getOperand(1).getReg())) {
175+
Target = *TargetRegState + Inst.getOperand(2).getImm();
176+
return true;
177+
}
178+
179+
return false;
180+
}
181+
143182
return false;
144183
}
145184

llvm/test/tools/llvm-objdump/ELF/RISCV/branches.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ c.jal bar
5757
c.j bar
5858

5959
# CHECK: auipc ra, 0
60-
# CHECK: jalr ra, 16(ra){{$}}
60+
# CHECK: jalr ra, 16(ra) <foo+0x58>
6161
call .Llocal
6262

6363
# CHECK: auipc ra, 0
64-
# CHECK: jalr ra, 16(ra){{$}}
64+
# CHECK: jalr ra, 16(ra) <bar>
6565
call bar
6666

6767
.Llocal:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s | \
2+
# RUN: llvm-objdump -d -M no-aliases --no-show-raw-insn - | \
3+
# RUN: FileCheck %s
4+
5+
## Test multiple interleaved auipc/jalr pairs
6+
# CHECK: auipc t0, 0
7+
1: auipc t0, %pcrel_hi(bar)
8+
# CHECK: auipc t1, 0
9+
2: auipc t1, %pcrel_hi(bar)
10+
# CHECK: jalr ra, 16(t0) <bar>
11+
jalr %pcrel_lo(1b)(t0)
12+
# CHECK: jalr ra, 12(t1) <bar>
13+
jalr %pcrel_lo(2b)(t1)
14+
15+
# CHECK-LABEL: <bar>:
16+
bar:
17+
# CHECK: c.nop
18+
nop

0 commit comments

Comments
 (0)