Skip to content

Commit c9ba781

Browse files
author
Yonghong Song
committed
Report an error by default instead of a warning
Report an error by default. Add a new flag -bpf-disable-check-unreachable-ir to disable checking. Depend on whether debuginfo is available or not, the error message will look like in func <func> from line <line num> to the end of func that code was deleted as unreachable, due to uninitialized variable? try -Wuninitialized? or in func <func> that code was deleted as unreachable, due to uninitialized variable? try -Wuninitialized?
1 parent fcbcd8e commit c9ba781

File tree

7 files changed

+141
-114
lines changed

7 files changed

+141
-114
lines changed

llvm/lib/Target/BPF/BPF.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class BPFTargetMachine;
2222
class InstructionSelector;
2323
class PassRegistry;
2424

25-
ModulePass *createBPFCheckUndefIR();
25+
ModulePass *createBPFCheckUnreachableIR();
2626
ModulePass *createBPFCheckAndAdjustIR();
2727

2828
FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
@@ -35,7 +35,7 @@ InstructionSelector *createBPFInstructionSelector(const BPFTargetMachine &,
3535
const BPFSubtarget &,
3636
const BPFRegisterBankInfo &);
3737

38-
void initializeBPFCheckUndefIRPass(PassRegistry &);
38+
void initializeBPFCheckUnreachableIRPass(PassRegistry &);
3939
void initializeBPFCheckAndAdjustIRPass(PassRegistry&);
4040
void initializeBPFDAGToDAGISelLegacyPass(PassRegistry &);
4141
void initializeBPFMIPeepholePass(PassRegistry &);

llvm/lib/Target/BPF/BPFCheckUndefIR.cpp

Lines changed: 0 additions & 102 deletions
This file was deleted.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//===--------- BPFCheckUnreachableIR.cpp - Issue Unreachable Error --------===//
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+
// Check 'unreachable' IRs and issue proper errors.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "BPF.h"
14+
#include "llvm/IR/Constants.h"
15+
#include "llvm/IR/DiagnosticInfo.h"
16+
#include "llvm/IR/Instruction.h"
17+
#include "llvm/IR/Module.h"
18+
#include "llvm/IR/Type.h"
19+
#include "llvm/IR/Value.h"
20+
#include "llvm/Pass.h"
21+
22+
#define DEBUG_TYPE "bpf-check-unreachable-ir"
23+
24+
using namespace llvm;
25+
26+
static cl::opt<bool>
27+
DisableCheckUnreachableIR("bpf-disable-check-unreachable-ir", cl::Hidden,
28+
cl::desc("BPF: Disable Checking Unreachable IR"),
29+
cl::init(false));
30+
31+
namespace {
32+
33+
class BPFCheckUnreachableIR final : public ModulePass {
34+
bool runOnModule(Module &F) override;
35+
36+
public:
37+
static char ID;
38+
BPFCheckUnreachableIR() : ModulePass(ID) {}
39+
40+
private:
41+
void BPFCheckUnreachableIRImpl(Function &F);
42+
void BPFCheckInst(Function &F, BasicBlock &BB, Instruction &I);
43+
void HandleUnreachableInsn(Function &F, BasicBlock &BB, Instruction &I);
44+
};
45+
} // End anonymous namespace
46+
47+
char BPFCheckUnreachableIR::ID = 0;
48+
INITIALIZE_PASS(BPFCheckUnreachableIR, DEBUG_TYPE, "BPF Check Unreachable IRs",
49+
false, false)
50+
51+
ModulePass *llvm::createBPFCheckUnreachableIR() {
52+
return new BPFCheckUnreachableIR();
53+
}
54+
55+
void BPFCheckUnreachableIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
56+
Instruction &I) {
57+
// LLVM may create a switch statement with default to a 'unreachable' basic
58+
// block. Do not warn for such cases.
59+
unsigned NumNoSwitches = 0, NumSwitches = 0;
60+
for (BasicBlock *Pred : predecessors(&BB)) {
61+
const Instruction *Term = Pred->getTerminator();
62+
if (Term && Term->getOpcode() == Instruction::Switch) {
63+
NumSwitches++;
64+
continue;
65+
}
66+
NumNoSwitches++;
67+
}
68+
if (NumSwitches > 0 && NumNoSwitches == 0)
69+
return;
70+
71+
// If the previous insn is no return, do not warn for such cases.
72+
// One example is __bpf_unreachable from libbpf bpf_headers.h.
73+
Instruction *PrevI = I.getPrevNonDebugInstruction();
74+
if (PrevI) {
75+
auto *CI = dyn_cast<CallInst>(PrevI);
76+
if (CI && CI->doesNotReturn())
77+
return;
78+
}
79+
80+
// Typically the 'unreachable' insn is the last insn in the function.
81+
// Find the closest line number to this insn and report such info to users.
82+
uint32_t LineNum = 0;
83+
for (Instruction &Insn : llvm::reverse(BB)) {
84+
const DebugLoc &DL = Insn.getDebugLoc();
85+
if (!DL || DL.getLine() == 0)
86+
continue;
87+
LineNum = DL.getLine();
88+
break;
89+
}
90+
91+
std::string LineInfo;
92+
if (LineNum)
93+
LineInfo = " from line " + std::to_string(LineNum) + " to the end of func";
94+
95+
F.getContext().diagnose(DiagnosticInfoGeneric(
96+
Twine("in func ")
97+
.concat(F.getName())
98+
.concat(LineInfo)
99+
.concat(" that code was deleted as unreachable,\n")
100+
.concat(" due to uninitialized variable?")
101+
.concat(" try -Wuninitialized?"),
102+
DS_Error));
103+
}
104+
105+
void BPFCheckUnreachableIR::BPFCheckInst(Function &F, BasicBlock &BB,
106+
Instruction &I) {
107+
if (I.getOpcode() == Instruction::Unreachable)
108+
HandleUnreachableInsn(F, BB, I);
109+
}
110+
111+
void BPFCheckUnreachableIR::BPFCheckUnreachableIRImpl(Function &F) {
112+
// A 'unreachable' will be added to the end of naked function.
113+
// Let ignore these naked functions.
114+
if (F.hasFnAttribute(Attribute::Naked))
115+
return;
116+
117+
for (auto &BB : F) {
118+
for (auto &I : BB)
119+
BPFCheckInst(F, BB, I);
120+
}
121+
}
122+
123+
bool BPFCheckUnreachableIR::runOnModule(Module &M) {
124+
if (DisableCheckUnreachableIR)
125+
return false;
126+
for (Function &F : M)
127+
BPFCheckUnreachableIRImpl(F);
128+
return false;
129+
}

llvm/lib/Target/BPF/BPFTargetMachine.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {
4545

4646
PassRegistry &PR = *PassRegistry::getPassRegistry();
4747
initializeGlobalISel(PR);
48-
initializeBPFCheckUndefIRPass(PR);
48+
initializeBPFCheckUnreachableIRPass(PR);
4949
initializeBPFCheckAndAdjustIRPass(PR);
5050
initializeBPFMIPeepholePass(PR);
5151
initializeBPFDAGToDAGISelLegacyPass(PR);
@@ -144,7 +144,7 @@ void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
144144
}
145145

146146
void BPFPassConfig::addIRPasses() {
147-
addPass(createBPFCheckUndefIR());
147+
addPass(createBPFCheckUnreachableIR());
148148
addPass(createAtomicExpandLegacyPass());
149149
addPass(createBPFCheckAndAdjustIR());
150150

llvm/lib/Target/BPF/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ add_llvm_target(BPFCodeGen
2626
BPFAsmPrinter.cpp
2727
BPFASpaceCastSimplifyPass.cpp
2828
BPFCheckAndAdjustIR.cpp
29-
BPFCheckUndefIR.cpp
29+
BPFCheckUnreachableIR.cpp
3030
BPFFrameLowering.cpp
3131
BPFInstrInfo.cpp
3232
BPFIRPeephole.cpp

llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ define dso_local void @normal() "frame-pointer"="all" {
3737
; CHECK-BE-NEXT: # %bb.0:
3838
; CHECK-BE-NEXT: call main
3939
call void @main()
40-
unreachable
40+
ret void
4141
}

llvm/test/CodeGen/BPF/store_imm.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ define void @byte(ptr %p0) {
1313
store volatile i8 1, ptr %p0, align 1
1414
store volatile i8 -1, ptr %p1, align 1
1515

16-
unreachable
16+
ret void
1717
}
1818

1919
define void @half(ptr, ptr %p0) {
@@ -26,7 +26,7 @@ define void @half(ptr, ptr %p0) {
2626
store volatile i16 1, ptr %p0, align 2
2727
store volatile i16 -1, ptr %p1, align 2
2828

29-
unreachable
29+
ret void
3030
}
3131

3232
define void @word(ptr, ptr, ptr %p0) {
@@ -47,7 +47,7 @@ define void @word(ptr, ptr, ptr %p0) {
4747
store volatile i32 4294967295, ptr %p3, align 4
4848
store volatile i32 4294967296, ptr %p3, align 4
4949

50-
unreachable
50+
ret void
5151
}
5252

5353
define void @dword(ptr, ptr, ptr, ptr %p0) {
@@ -69,7 +69,7 @@ define void @dword(ptr, ptr, ptr, ptr %p0) {
6969
store volatile i64 -2000000000, ptr %p2, align 8
7070
store volatile i64 4294967295, ptr %p3, align 8
7171

72-
unreachable
72+
ret void
7373
}
7474

7575
define void @unaligned(ptr %p0) {
@@ -88,7 +88,7 @@ define void @unaligned(ptr %p0) {
8888
store volatile i32 -2, ptr %p1, align 2
8989
store volatile i64 -2, ptr %p2, align 4
9090

91-
unreachable
91+
ret void
9292
}
9393

9494
define void @inline_asm(ptr %p0) {
@@ -100,5 +100,5 @@ define void @inline_asm(ptr %p0) {
100100
; CHECK-NEXT: #NO_APP
101101
call void asm "*(u32 *)(r0 + 42) = 7;", "~{r0},~{mem}"()
102102

103-
unreachable
103+
ret void
104104
}

0 commit comments

Comments
 (0)