[llvm] [BPF] Report an error if comparison imm operand cannot fit in 32bit (PR #142989)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 9 22:52:29 PDT 2025
https://github.com/yonghong-song updated https://github.com/llvm/llvm-project/pull/142989
>From 5148d259c50001eacb5971d76035c93f4ef653ac Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Wed, 4 Jun 2025 16:22:53 -0700
Subject: [PATCH] [BPF] Report warning for some insn imm requiring int range in
inline asm
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
For clang, we do not want to issue an error since it may break
backward compatability. So the below warning is issued:
warning: immediate out of range, shall fit in int range
Some ALU/COND/ST insns are checked.
[1] https://lore.kernel.org/bpf/f93ce37e-e155-4165-88e2-1a3cadee7c82@linux.dev/
---
.../BPF/MCTargetDesc/BPFMCCodeEmitter.cpp | 60 +++++++++++++++++--
llvm/test/CodeGen/BPF/warn-cmp.ll | 43 +++++++++++++
2 files changed, 97 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/BPF/warn-cmp.ll
diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
index 10a46f100bbea..c68b6047bfbe3 100644
--- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
+++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
@@ -14,6 +14,7 @@
#include "MCTargetDesc/BPFMCTargetDesc.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
@@ -33,11 +34,12 @@ namespace {
class BPFMCCodeEmitter : public MCCodeEmitter {
const MCRegisterInfo &MRI;
bool IsLittleEndian;
+ MCContext &Ctx;
public:
BPFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri,
- bool IsLittleEndian)
- : MRI(mri), IsLittleEndian(IsLittleEndian) { }
+ bool IsLittleEndian, MCContext &ctx)
+ : MRI(mri), IsLittleEndian(IsLittleEndian), Ctx(ctx) {}
BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;
void operator=(const BPFMCCodeEmitter &) = delete;
~BPFMCCodeEmitter() override = default;
@@ -58,6 +60,8 @@ class BPFMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void checkImmRange(const MCInst &MI, int64_t Imm) const;
+
void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
@@ -67,12 +71,53 @@ class BPFMCCodeEmitter : public MCCodeEmitter {
MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
- return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true);
+ return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true, Ctx);
}
MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
- return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false);
+ return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false, Ctx);
+}
+
+void BPFMCCodeEmitter::checkImmRange(const MCInst &MI, int64_t Imm) const {
+ switch (MI.getOpcode()) {
+ // ALU/ALU64 insns
+ case BPF::MOV_ri:
+ case BPF::ADD_ri:
+ case BPF::SUB_ri:
+ case BPF::OR_ri:
+ case BPF::AND_ri:
+ case BPF::SLL_ri:
+ case BPF::SRL_ri:
+ case BPF::XOR_ri:
+ case BPF::SRA_ri:
+ case BPF::MUL_ri:
+ case BPF::SDIV_ri:
+ case BPF::SMOD_ri:
+ case BPF::SDIV_ri_32:
+ case BPF::SMOD_ri_32:
+ // Conditional insns
+ case BPF::JEQ_ri:
+ case BPF::JNE_ri:
+ case BPF::JSGT_ri:
+ case BPF::JSGE_ri:
+ case BPF::JSLT_ri:
+ case BPF::JSLE_ri:
+ case BPF::JEQ_ri_32:
+ case BPF::JNE_ri_32:
+ case BPF::JSGT_ri_32:
+ case BPF::JSGE_ri_32:
+ case BPF::JSLT_ri_32:
+ case BPF::JSLE_ri_32:
+ // Store insns
+ case BPF::STD_imm:
+ if (Imm < INT_MIN || Imm > INT_MAX)
+ Ctx.reportWarning(MI.getLoc(),
+ "immediate out of range, shall fit in int range");
+ [[fallthrough]];
+ default:
+ break;
+ }
}
unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
@@ -81,8 +126,11 @@ unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
const MCSubtargetInfo &STI) const {
if (MO.isReg())
return MRI.getEncodingValue(MO.getReg());
- if (MO.isImm())
- return static_cast<unsigned>(MO.getImm());
+ if (MO.isImm()) {
+ int64_t Imm = MO.getImm();
+ checkImmRange(MI, Imm);
+ return static_cast<unsigned>(Imm);
+ }
assert(MO.isExpr());
diff --git a/llvm/test/CodeGen/BPF/warn-cmp.ll b/llvm/test/CodeGen/BPF/warn-cmp.ll
new file mode 100644
index 0000000000000..93bef0246a9db
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/warn-cmp.ll
@@ -0,0 +1,43 @@
+; RUN: llc -mtriple=bpfel -filetype=obj < %s 2>&1 >/dev/null | FileCheck %s
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test() naked {
+ tail call void asm sideeffect
+ "r1 = 40; if r1 == 0x1deadbeef goto +0; r0 = 0; exit;", "~{r0},~{r1}"()
+ unreachable
+}
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test_sdiv_1() naked {
+ tail call void asm sideeffect
+ "r1 = 40; r1 s/= 0xdeadbeef; r0 = 0; exit;", "~{r0},~{r1}"()
+ unreachable
+}
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test_sdiv_2() naked {
+ tail call void asm sideeffect
+ "w1 = 40; w1 s/= 0xdeadbeef; w0 = 0; exit;", "~{w0},~{w1}"()
+ unreachable
+}
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test_eq() naked {
+ tail call void asm sideeffect
+ "r1 = 40; if r1 == 0x1deadbeef goto +0; r0 = 0; exit;", "~{r0},~{r1}"()
+ unreachable
+}
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test_sge() naked {
+ tail call void asm sideeffect
+ "r1 = 40; if r1 s>= 0xdeadbeef goto +0; r0 = 0; exit;", "~{r0},~{r1}"()
+ unreachable
+}
+
+; CHECK: warning: immediate out of range, shall fit in int range
+define dso_local void @test_st() naked {
+ tail call void asm sideeffect
+ "*(u64 *)(r1 + 0) = 0xdeadbeef; r0 = 0; exit;", "~{r0},~{memory}"()
+ unreachable
+}
More information about the llvm-commits
mailing list