Skip to content

Commit 2f1e6eb

Browse files
[BPF] Report an warning if certain insn imm operand cannot fit in 32bit (#142989)
Ihor Solodrai reported a case ([1]) where gcc reports an error but clang ignores that error and proceeds to generate incorrect code. More specifically, the problematic code looks like: if r1 == 0xcafefeeddeadbeef goto <label> Here, 0xcafefeeddeadbeef needs to be encoded in a 32-bit imm field of the insns and the 32-bit imm allows sign extenstion to 64-bit imm. Obviously, 0xcafefeeddeadbeef cannot encode properly. The compilation failed for gcc with the following error: Error: immediate out of range, shall fit in 32 bits Given a 64-bit imm value, converting to the proper 32-bit imm value must satisfy the following 64-bit patterns: 00000000 00000000 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 11111111 11111111 11111111 11111111 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx So if the top 32-bits is 0 or the top 33-bits is 0x1ffffffff, then the 64-bit imm value can be truncated into proper 32-bit imm. Otherwise, a warning message, the same as gcc, will be issued. If -Werror is enabled during compilation, the warning will turn into an error. [1] https://lore.kernel.org/bpf/[email protected]/
1 parent a08de42 commit 2f1e6eb

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "MCTargetDesc/BPFMCTargetDesc.h"
1515
#include "llvm/ADT/SmallVector.h"
1616
#include "llvm/MC/MCCodeEmitter.h"
17+
#include "llvm/MC/MCContext.h"
1718
#include "llvm/MC/MCExpr.h"
1819
#include "llvm/MC/MCFixup.h"
1920
#include "llvm/MC/MCInst.h"
@@ -33,11 +34,12 @@ namespace {
3334
class BPFMCCodeEmitter : public MCCodeEmitter {
3435
const MCRegisterInfo &MRI;
3536
bool IsLittleEndian;
37+
MCContext &Ctx;
3638

3739
public:
3840
BPFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri,
39-
bool IsLittleEndian)
40-
: MRI(mri), IsLittleEndian(IsLittleEndian) { }
41+
bool IsLittleEndian, MCContext &ctx)
42+
: MRI(mri), IsLittleEndian(IsLittleEndian), Ctx(ctx) {}
4143
BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;
4244
void operator=(const BPFMCCodeEmitter &) = delete;
4345
~BPFMCCodeEmitter() override = default;
@@ -67,12 +69,12 @@ class BPFMCCodeEmitter : public MCCodeEmitter {
6769

6870
MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,
6971
MCContext &Ctx) {
70-
return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true);
72+
return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true, Ctx);
7173
}
7274

7375
MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,
7476
MCContext &Ctx) {
75-
return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false);
77+
return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false, Ctx);
7678
}
7779

7880
unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
@@ -81,8 +83,16 @@ unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
8183
const MCSubtargetInfo &STI) const {
8284
if (MO.isReg())
8385
return MRI.getEncodingValue(MO.getReg());
84-
if (MO.isImm())
85-
return static_cast<unsigned>(MO.getImm());
86+
if (MO.isImm()) {
87+
uint64_t Imm = MO.getImm();
88+
uint64_t High32Bits = Imm >> 32, High33Bits = Imm >> 31;
89+
if (MI.getOpcode() != BPF::LD_imm64 && High32Bits != 0 &&
90+
High33Bits != 0x1FFFFFFFFULL) {
91+
Ctx.reportWarning(MI.getLoc(),
92+
"immediate out of range, shall fit in 32 bits");
93+
}
94+
return static_cast<unsigned>(Imm);
95+
}
8696

8797
assert(MO.isExpr());
8898

llvm/test/CodeGen/BPF/warn-cmp.ll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; RUN: llc -mtriple=bpfel -filetype=obj < %s 2>&1 >/dev/null | FileCheck %s
2+
3+
; CHECK: warning: immediate out of range, shall fit in 32 bits
4+
define dso_local void @test_1() naked {
5+
tail call void asm sideeffect
6+
"r1 = 40; if r1 == 0x1deadbeef goto +0; r0 = 0; exit;", "~{r0},~{r1}"()
7+
unreachable
8+
}
9+
10+
; CHECK: warning: immediate out of range, shall fit in 32 bits
11+
define dso_local void @test_2() naked {
12+
tail call void asm sideeffect
13+
"r1 = 40; if r1 == 0xffffffff00000000 goto +0; r0 = 0; exit;", "~{r0},~{r1}"()
14+
unreachable
15+
}

0 commit comments

Comments
 (0)