Skip to content

Commit

Permalink
Report an error by default instead of a warning
Browse files Browse the repository at this point in the history
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?
  • Loading branch information
Yonghong Song committed Feb 22, 2025
1 parent fcbcd8e commit c9ba781
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 114 deletions.
4 changes: 2 additions & 2 deletions llvm/lib/Target/BPF/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class BPFTargetMachine;
class InstructionSelector;
class PassRegistry;

ModulePass *createBPFCheckUndefIR();
ModulePass *createBPFCheckUnreachableIR();
ModulePass *createBPFCheckAndAdjustIR();

FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
Expand All @@ -35,7 +35,7 @@ InstructionSelector *createBPFInstructionSelector(const BPFTargetMachine &,
const BPFSubtarget &,
const BPFRegisterBankInfo &);

void initializeBPFCheckUndefIRPass(PassRegistry &);
void initializeBPFCheckUnreachableIRPass(PassRegistry &);
void initializeBPFCheckAndAdjustIRPass(PassRegistry&);
void initializeBPFDAGToDAGISelLegacyPass(PassRegistry &);
void initializeBPFMIPeepholePass(PassRegistry &);
Expand Down
102 changes: 0 additions & 102 deletions llvm/lib/Target/BPF/BPFCheckUndefIR.cpp

This file was deleted.

129 changes: 129 additions & 0 deletions llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//===--------- BPFCheckUnreachableIR.cpp - Issue Unreachable Error --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Check 'unreachable' IRs and issue proper errors.
//
//===----------------------------------------------------------------------===//

#include "BPF.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Pass.h"

#define DEBUG_TYPE "bpf-check-unreachable-ir"

using namespace llvm;

static cl::opt<bool>
DisableCheckUnreachableIR("bpf-disable-check-unreachable-ir", cl::Hidden,
cl::desc("BPF: Disable Checking Unreachable IR"),
cl::init(false));

namespace {

class BPFCheckUnreachableIR final : public ModulePass {
bool runOnModule(Module &F) override;

public:
static char ID;
BPFCheckUnreachableIR() : ModulePass(ID) {}

private:
void BPFCheckUnreachableIRImpl(Function &F);
void BPFCheckInst(Function &F, BasicBlock &BB, Instruction &I);
void HandleUnreachableInsn(Function &F, BasicBlock &BB, Instruction &I);
};
} // End anonymous namespace

char BPFCheckUnreachableIR::ID = 0;
INITIALIZE_PASS(BPFCheckUnreachableIR, DEBUG_TYPE, "BPF Check Unreachable IRs",
false, false)

ModulePass *llvm::createBPFCheckUnreachableIR() {
return new BPFCheckUnreachableIR();
}

void BPFCheckUnreachableIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
Instruction &I) {
// LLVM may create a switch statement with default to a 'unreachable' basic
// block. Do not warn for such cases.
unsigned NumNoSwitches = 0, NumSwitches = 0;
for (BasicBlock *Pred : predecessors(&BB)) {
const Instruction *Term = Pred->getTerminator();
if (Term && Term->getOpcode() == Instruction::Switch) {
NumSwitches++;
continue;
}
NumNoSwitches++;
}
if (NumSwitches > 0 && NumNoSwitches == 0)
return;

// If the previous insn is no return, do not warn for such cases.
// One example is __bpf_unreachable from libbpf bpf_headers.h.
Instruction *PrevI = I.getPrevNonDebugInstruction();
if (PrevI) {
auto *CI = dyn_cast<CallInst>(PrevI);
if (CI && CI->doesNotReturn())
return;
}

// Typically the 'unreachable' insn is the last insn in the function.
// Find the closest line number to this insn and report such info to users.
uint32_t LineNum = 0;
for (Instruction &Insn : llvm::reverse(BB)) {
const DebugLoc &DL = Insn.getDebugLoc();
if (!DL || DL.getLine() == 0)
continue;
LineNum = DL.getLine();
break;
}

std::string LineInfo;
if (LineNum)
LineInfo = " from line " + std::to_string(LineNum) + " to the end of func";

F.getContext().diagnose(DiagnosticInfoGeneric(
Twine("in func ")
.concat(F.getName())
.concat(LineInfo)
.concat(" that code was deleted as unreachable,\n")
.concat(" due to uninitialized variable?")
.concat(" try -Wuninitialized?"),
DS_Error));
}

void BPFCheckUnreachableIR::BPFCheckInst(Function &F, BasicBlock &BB,
Instruction &I) {
if (I.getOpcode() == Instruction::Unreachable)
HandleUnreachableInsn(F, BB, I);
}

void BPFCheckUnreachableIR::BPFCheckUnreachableIRImpl(Function &F) {
// A 'unreachable' will be added to the end of naked function.
// Let ignore these naked functions.
if (F.hasFnAttribute(Attribute::Naked))
return;

for (auto &BB : F) {
for (auto &I : BB)
BPFCheckInst(F, BB, I);
}
}

bool BPFCheckUnreachableIR::runOnModule(Module &M) {
if (DisableCheckUnreachableIR)
return false;
for (Function &F : M)
BPFCheckUnreachableIRImpl(F);
return false;
}
4 changes: 2 additions & 2 deletions llvm/lib/Target/BPF/BPFTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {

PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeGlobalISel(PR);
initializeBPFCheckUndefIRPass(PR);
initializeBPFCheckUnreachableIRPass(PR);
initializeBPFCheckAndAdjustIRPass(PR);
initializeBPFMIPeepholePass(PR);
initializeBPFDAGToDAGISelLegacyPass(PR);
Expand Down Expand Up @@ -144,7 +144,7 @@ void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
}

void BPFPassConfig::addIRPasses() {
addPass(createBPFCheckUndefIR());
addPass(createBPFCheckUnreachableIR());
addPass(createAtomicExpandLegacyPass());
addPass(createBPFCheckAndAdjustIR());

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/BPF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ add_llvm_target(BPFCodeGen
BPFAsmPrinter.cpp
BPFASpaceCastSimplifyPass.cpp
BPFCheckAndAdjustIR.cpp
BPFCheckUndefIR.cpp
BPFCheckUnreachableIR.cpp
BPFFrameLowering.cpp
BPFInstrInfo.cpp
BPFIRPeephole.cpp
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ define dso_local void @normal() "frame-pointer"="all" {
; CHECK-BE-NEXT: # %bb.0:
; CHECK-BE-NEXT: call main
call void @main()
unreachable
ret void
}
12 changes: 6 additions & 6 deletions llvm/test/CodeGen/BPF/store_imm.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ define void @byte(ptr %p0) {
store volatile i8 1, ptr %p0, align 1
store volatile i8 -1, ptr %p1, align 1

unreachable
ret void
}

define void @half(ptr, ptr %p0) {
Expand All @@ -26,7 +26,7 @@ define void @half(ptr, ptr %p0) {
store volatile i16 1, ptr %p0, align 2
store volatile i16 -1, ptr %p1, align 2

unreachable
ret void
}

define void @word(ptr, ptr, ptr %p0) {
Expand All @@ -47,7 +47,7 @@ define void @word(ptr, ptr, ptr %p0) {
store volatile i32 4294967295, ptr %p3, align 4
store volatile i32 4294967296, ptr %p3, align 4

unreachable
ret void
}

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

unreachable
ret void
}

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

unreachable
ret void
}

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

unreachable
ret void
}

0 comments on commit c9ba781

Please sign in to comment.