Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC][BPF] Report Unreachable Behavior from IR #126858

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/lib/Target/BPF/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class BPFTargetMachine;
class InstructionSelector;
class PassRegistry;

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

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

void initializeBPFCheckUnreachableIRPass(PassRegistry &);
void initializeBPFCheckAndAdjustIRPass(PassRegistry&);
void initializeBPFDAGToDAGISelLegacyPass(PassRegistry &);
void initializeBPFMIPeepholePass(PassRegistry &);
Expand Down
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 function";

F.getContext().diagnose(DiagnosticInfoGeneric(
Twine("in function ")
.concat("\"" + F.getName() + "\"")
.concat(LineInfo)
.concat(" that code was deleted as unreachable.\n")
.concat(" due to uninitialized variable? 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;
}
2 changes: 2 additions & 0 deletions llvm/lib/Target/BPF/BPFTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {

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

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

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/BPF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_llvm_target(BPFCodeGen
BPFAsmPrinter.cpp
BPFASpaceCastSimplifyPass.cpp
BPFCheckAndAdjustIR.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
}
Loading