diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h index a1f97d83e857c..10a4a14571f33 100644 --- a/llvm/lib/Target/BPF/BPF.h +++ b/llvm/lib/Target/BPF/BPF.h @@ -22,7 +22,7 @@ class BPFTargetMachine; class InstructionSelector; class PassRegistry; -ModulePass *createBPFCheckUndefIR(); +ModulePass *createBPFCheckUnreachableIR(); ModulePass *createBPFCheckAndAdjustIR(); FunctionPass *createBPFISelDag(BPFTargetMachine &TM); @@ -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 &); diff --git a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp deleted file mode 100644 index 5653959eb314d..0000000000000 --- a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===---------------- BPFAdjustOpt.cpp - Adjust Optimization --------------===// -// -// 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 warnings. -// -//===----------------------------------------------------------------------===// - -#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-undef-ir" - -using namespace llvm; - -namespace { - -class BPFCheckUndefIR final : public ModulePass { - bool runOnModule(Module &F) override; - -public: - static char ID; - BPFCheckUndefIR() : ModulePass(ID) {} - -private: - void BPFCheckUndefIRImpl(Function &F); - void BPFCheckInst(Function &F, BasicBlock &BB, Instruction &I); - void HandleUnreachableInsn(Function &F, BasicBlock &BB, Instruction &I); -}; -} // End anonymous namespace - -char BPFCheckUndefIR::ID = 0; -INITIALIZE_PASS(BPFCheckUndefIR, DEBUG_TYPE, "BPF Check Undef IRs", false, - false) - -ModulePass *llvm::createBPFCheckUndefIR() { return new BPFCheckUndefIR(); } - -void BPFCheckUndefIR::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(PrevI); - if (CI && CI->doesNotReturn()) - return; - } - - F.getContext().diagnose( - DiagnosticInfoGeneric(Twine("unreachable in func ") - .concat(F.getName()) - .concat(", due to uninitialized variable?"), - DS_Warning)); -} - -void BPFCheckUndefIR::BPFCheckInst(Function &F, BasicBlock &BB, - Instruction &I) { - if (I.getOpcode() == Instruction::Unreachable) - HandleUnreachableInsn(F, BB, I); -} - -void BPFCheckUndefIR::BPFCheckUndefIRImpl(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 BPFCheckUndefIR::runOnModule(Module &M) { - for (Function &F : M) - BPFCheckUndefIRImpl(F); - return false; -} diff --git a/llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp b/llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp new file mode 100644 index 0000000000000..c0d57924c79f7 --- /dev/null +++ b/llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp @@ -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 + 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(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; +} diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp index 6523086ef10c0..4ca4600fbe566 100644 --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -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); @@ -144,7 +144,7 @@ void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { } void BPFPassConfig::addIRPasses() { - addPass(createBPFCheckUndefIR()); + addPass(createBPFCheckUnreachableIR()); addPass(createAtomicExpandLegacyPass()); addPass(createBPFCheckAndAdjustIR()); diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index edc8290b7cf7c..1babf59ee0d81 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -26,7 +26,7 @@ add_llvm_target(BPFCodeGen BPFAsmPrinter.cpp BPFASpaceCastSimplifyPass.cpp BPFCheckAndAdjustIR.cpp - BPFCheckUndefIR.cpp + BPFCheckUnreachableIR.cpp BPFFrameLowering.cpp BPFInstrInfo.cpp BPFIRPeephole.cpp diff --git a/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll index 4e4436296f3b5..253b321171ba4 100644 --- a/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll +++ b/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll @@ -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 } diff --git a/llvm/test/CodeGen/BPF/store_imm.ll b/llvm/test/CodeGen/BPF/store_imm.ll index dba83937837b6..efcbd9a4f2d53 100644 --- a/llvm/test/CodeGen/BPF/store_imm.ll +++ b/llvm/test/CodeGen/BPF/store_imm.ll @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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 }