[llvm] [BPF] Report Unreachable Behavior from IR (PR #126858)

via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 21 11:17:20 PST 2025


https://github.com/yonghong-song updated https://github.com/llvm/llvm-project/pull/126858

>From 7998775e64e67f6dd3b1b68c7f5004891cc08ade Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Mon, 10 Feb 2025 09:45:37 -0800
Subject: [PATCH 1/4] [BPF] Report Undefined Behavior from IR
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Marc Suñé (Isovalent, part of Cisco) reported an issue where an
uninitialized variable caused generated bpf prog binary code not
working as expected. The reproducer is in [1] where the flags
“-Wall -Werror” are enabled, but there is no warning and compiler
may take advantage of uninit variable to do aggressive optimization.

In discussion [2], various approaches are discussed, e.g., improving
compiler to detect undefined behavior due to uninitialized variables,
trying to use ubsan (-fsanitize=undefined), and making
-ftrivial-auto-var-init=zero as the bpf default flags.

I tried [3] with -ftrivial-auto-var-init=zero and eventually we
decided no-go since first it may introduce performance regression
and second the prog may still be wrong if the prog expects a
non-zero value. The ubsan apprach seems not working as well
since it involves runtime callback func ([4]).

The approach here is not to do complicate compiler analysis to detect
whether where is undef behavior which may impact final codegen.
Rather, we relies on compiler to do its normal transformation
and at later IR passes stage, a BPF backend pass is inserted to
check whether undef behavior is in IR or not. Note that
if undef behavior indeed impacts codes, the compiler will discard
those related codes with simple 'undef' or 'unreachable'.

For example, for the case [1], before SCCPPass, the IR looks like
```
define dso_local i32 @repro(ptr noundef %0) #0 section "classifier" {
  %2 = alloca %struct.ipv6_opt_hdr, align 8
  %3 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt, i32 noundef 6) #2
  %4 = tail call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76) #2, !srcloc !3
  %5 = ptrtoint ptr %4 to i64
  %6 = trunc i64 %5 to i32
  %7 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt, i32 noundef 23) #2
  call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %2) #2
  %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
  switch i8 undef, label %51 [
    i8 59, label %56
    i8 44, label %57
    i8 0, label %9
    i8 43, label %9
    i8 51, label %9
    i8 60, label %9
  ]

9:                                                ; preds = %1, %1, %1, %1
  %10 = sub i32 40, %6
  ...
```
Note that 'undef' is used for switch key due to one of early pass LoopFullUnrollPass.
After SCCPPass:
```
efine dso_local i32 @repro(ptr noundef %0) #0 section "classifier" {
  %2 = alloca %struct.ipv6_opt_hdr, align 8
  %3 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt, i32 noundef 6) #2
  %4 = tail call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76) #2, !srcloc !3
  %5 = ptrtoint ptr %4 to i64
  %6 = trunc i64 %5 to i32
  %7 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt, i32 noundef 23) #2
  call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %2) #2
  %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
  unreachable
}
```

For another example,
```
$ cat t.c
int foo() {
  int i[2];
  return i[1];
}

```
Before SROAPass pass,
```
define dso_local i32 @foo() #0 {
  %1 = alloca [2 x i32], align 4
  call void @llvm.lifetime.start.p0(i64 8, ptr %1) #2
  %2 = getelementptr inbounds [2 x i32], ptr %1, i64 0, i64 1
  %3 = load i32, ptr %2, align 4, !tbaa !3
  call void @llvm.lifetime.end.p0(i64 8, ptr %1) #2
  ret i32 %3
}
```
After SROAPass pass,
```
define dso_local i32 @foo() #0 {
  ret i32 undef
}
```

Besides the above two test cases, the following three patterns are also covered:
  - It is possible llvm may generate codes where a default branch to 'unreachable' location.
    Ignore such 'unreachable' instances. See [5] or some comments in [2].
  - Handle pattern like __bpf_unreachable (defined in bpf_helpers.h).
  - Functions with naked attribute will have 'unreachable' at the end of function.
    Ignore such functions.

Tested with bpf selftests and there are no warnings issued.

  [1] https://github.com/msune/clang_bpf/blob/main/Makefile#L3
  [2] https://discourse.llvm.org/t/detect-undefined-behavior-due-to-uninitialized-variables-in-bpf-programs/84116?u=yonghong-song
  [3] https://github.com/llvm/llvm-project/pull/125601
  [4] https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/ubsan/ubsan_interface.inc
  [5] https://lore.kernel.org/lkml/0bf90fc0-2287-4ce0-b810-6e383e695981@linux.dev/
---
 llvm/lib/Target/BPF/BPF.h                |   2 +
 llvm/lib/Target/BPF/BPFCheckUndefIR.cpp  | 118 ++++++++++++++++
 llvm/lib/Target/BPF/BPFTargetMachine.cpp |   2 +
 llvm/lib/Target/BPF/CMakeLists.txt       |   1 +
 llvm/test/CodeGen/BPF/undef-sccp.ll      | 172 +++++++++++++++++++++++
 llvm/test/CodeGen/BPF/undef-sroa.ll      |  14 ++
 6 files changed, 309 insertions(+)
 create mode 100644 llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
 create mode 100644 llvm/test/CodeGen/BPF/undef-sccp.ll
 create mode 100644 llvm/test/CodeGen/BPF/undef-sroa.ll

diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h
index f07ae4c9baf1c..a1f97d83e857c 100644
--- a/llvm/lib/Target/BPF/BPF.h
+++ b/llvm/lib/Target/BPF/BPF.h
@@ -22,6 +22,7 @@ class BPFTargetMachine;
 class InstructionSelector;
 class PassRegistry;
 
+ModulePass *createBPFCheckUndefIR();
 ModulePass *createBPFCheckAndAdjustIR();
 
 FunctionPass *createBPFISelDag(BPFTargetMachine &TM);
@@ -34,6 +35,7 @@ InstructionSelector *createBPFInstructionSelector(const BPFTargetMachine &,
                                                   const BPFSubtarget &,
                                                   const BPFRegisterBankInfo &);
 
+void initializeBPFCheckUndefIRPass(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
new file mode 100644
index 0000000000000..d7bbadba4663d
--- /dev/null
+++ b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
@@ -0,0 +1,118 @@
+//===---------------- 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 'undef' and 'unreachable' IRs and issue proper warnings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "llvm/IR/Constants.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 HandleReturnInsn(Function &F, ReturnInst *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::HandleReturnInsn(Function &F, ReturnInst *I) {
+  Value *RetValue = I->getReturnValue();
+  // PoisonValue is a special UndefValue where compiler intentionally to
+  // poisons a value since it shouldn't be used.
+  if (!RetValue || isa<PoisonValue>(RetValue) || !isa<UndefValue>(RetValue))
+    return;
+
+  dbgs() << "WARNING: return undefined value in func " << F.getName()
+         << ", due to uninitialized variable?\n";
+}
+
+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<CallInst>(PrevI);
+    if (CI && CI->doesNotReturn())
+      return;
+  }
+
+  dbgs() << "WARNING: unreachable in func " << F.getName()
+         << ", due to uninitialized variable?\n";
+}
+
+void BPFCheckUndefIR::BPFCheckInst(Function &F, BasicBlock &BB,
+                                   Instruction &I) {
+  switch (I.getOpcode()) {
+  case Instruction::Ret:
+    HandleReturnInsn(F, cast<ReturnInst>(&I));
+    break;
+  case Instruction::Unreachable:
+    HandleUnreachableInsn(F, BB, I);
+    break;
+  default:
+    break;
+  }
+}
+
+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/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index 3379af6fe8744..6523086ef10c0 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -45,6 +45,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() {
 
   PassRegistry &PR = *PassRegistry::getPassRegistry();
   initializeGlobalISel(PR);
+  initializeBPFCheckUndefIRPass(PR);
   initializeBPFCheckAndAdjustIRPass(PR);
   initializeBPFMIPeepholePass(PR);
   initializeBPFDAGToDAGISelLegacyPass(PR);
@@ -143,6 +144,7 @@ void BPFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 }
 
 void BPFPassConfig::addIRPasses() {
+  addPass(createBPFCheckUndefIR());
   addPass(createAtomicExpandLegacyPass());
   addPass(createBPFCheckAndAdjustIR());
 
diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt
index eade4cacb7100..edc8290b7cf7c 100644
--- a/llvm/lib/Target/BPF/CMakeLists.txt
+++ b/llvm/lib/Target/BPF/CMakeLists.txt
@@ -26,6 +26,7 @@ add_llvm_target(BPFCodeGen
   BPFAsmPrinter.cpp
   BPFASpaceCastSimplifyPass.cpp
   BPFCheckAndAdjustIR.cpp
+  BPFCheckUndefIR.cpp
   BPFFrameLowering.cpp
   BPFInstrInfo.cpp
   BPFIRPeephole.cpp
diff --git a/llvm/test/CodeGen/BPF/undef-sccp.ll b/llvm/test/CodeGen/BPF/undef-sccp.ll
new file mode 100644
index 0000000000000..1cc6950fe304d
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/undef-sccp.ll
@@ -0,0 +1,172 @@
+; RUN: opt -S -passes='sccp' %s -o %t1
+; RUN: opt --bpf-check-undef-ir -S -mtriple=bpf-pc-linux %t1 >& %t2
+; RUN: cat %t2 | FileCheck -check-prefixes=CHECK %s
+
+%union.v6addr = type { %struct.anon.1 }
+%struct.anon.1 = type { i64, i64 }
+%union.macaddr = type { %struct.anon }
+%struct.anon = type { i32, i16 }
+%struct.icmp6hdr = type { i8, i8, i16, %union.anon }
+%union.anon = type { [1 x i32] }
+%struct.ipv6_opt_hdr = type { i8, i8 }
+
+ at repro.____fmt = internal constant [6 x i8] c"Start\00", align 1
+ at repro.____fmt.1 = internal constant [4 x i8] c"End\00", align 1
+ at __packed = dso_local global %union.v6addr zeroinitializer, align 8
+ at icmp6_ndisc_validate.____fmt = internal constant [23 x i8] c"pre ipv6_hdrlen_offset\00", align 1
+ at icmp6_ndisc_validate.____fmt.2 = internal constant [24 x i8] c"post ipv6_hdrlen_offset\00", align 1
+ at icmp6_ndisc_validate.____fmt.3 = internal constant [5 x i8] c"KO 1\00", align 1
+ at icmp6_ndisc_validate.____fmt.4 = internal constant [5 x i8] c"KO 2\00", align 1
+ at icmp6_ndisc_validate.____fmt.5 = internal constant [5 x i8] c"ACK \00", align 1
+ at ipv6_hdrlen_offset.____fmt = internal constant [17 x i8] c"OKOK %d, len: %d\00", align 1
+ at ipv6_hdrlen_offset.____fmt.6 = internal constant [18 x i8] c"KO INVALID EXTHDR\00", align 1
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @repro], section "llvm.metadata"
+
+define dso_local i32 @repro(ptr noundef %0) section "classifier" {
+  %2 = alloca %struct.ipv6_opt_hdr, align 8
+  %3 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt, i32 noundef 6)
+  %4 = tail call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76)
+  %5 = ptrtoint ptr %4 to i64
+  %6 = trunc i64 %5 to i32
+  %7 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt, i32 noundef 23)
+  call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %2)
+  %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
+  switch i8 undef, label %51 [
+    i8 59, label %56
+    i8 44, label %57
+    i8 0, label %9
+    i8 43, label %9
+    i8 51, label %9
+    i8 60, label %9
+  ]
+
+; CHECK:       unreachable in func repro, due to uninitialized variable?
+; CHECK:       %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
+; CHECK-NEXT:  unreachable
+
+9:                                                ; preds = %1, %1, %1, %1
+  %10 = sub i32 40, %6
+  %11 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %10, ptr noundef nonnull %2, i32 noundef 2)
+  %12 = icmp slt i64 %11, 0
+  br i1 %12, label %57, label %13
+
+13:                                               ; preds = %9
+  %14 = load i8, ptr %8, align 1
+  %15 = zext i8 %14 to i32
+  %16 = shl nuw nsw i32 %15, 3
+  %17 = add nuw nsw i32 48, %16
+  %18 = load i8, ptr %2, align 1
+  switch i8 %18, label %51 [
+    i8 59, label %56
+    i8 44, label %57
+    i8 0, label %19
+    i8 43, label %19
+    i8 51, label %19
+    i8 60, label %19
+  ]
+
+19:                                               ; preds = %13, %13, %13, %13
+  %20 = sub i32 %17, %6
+  %21 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %20, ptr noundef nonnull %2, i32 noundef 2)
+  %22 = icmp slt i64 %21, 0
+  br i1 %22, label %57, label %23
+
+23:                                               ; preds = %19
+  %24 = icmp eq i8 %18, 51
+  %25 = load i8, ptr %8, align 1
+  %26 = zext i8 %25 to i32
+  %27 = select i1 %24, i32 2, i32 3
+  %28 = shl nuw nsw i32 %26, %27
+  %29 = add nuw nsw i32 %17, 8
+  %30 = add nuw nsw i32 %29, %28
+  %31 = load i8, ptr %2, align 1
+  switch i8 %31, label %51 [
+    i8 59, label %56
+    i8 44, label %57
+    i8 0, label %32
+    i8 43, label %32
+    i8 51, label %32
+    i8 60, label %32
+  ]
+
+32:                                               ; preds = %23, %23, %23, %23
+  %33 = sub i32 %30, %6
+  %34 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %33, ptr noundef nonnull %2, i32 noundef 2)
+  %35 = icmp slt i64 %34, 0
+  br i1 %35, label %57, label %36
+
+36:                                               ; preds = %32
+  %37 = icmp eq i8 %31, 51
+  %38 = load i8, ptr %8, align 1
+  %39 = zext i8 %38 to i32
+  %40 = select i1 %37, i32 2, i32 3
+  %41 = shl nuw nsw i32 %39, %40
+  %42 = add nuw nsw i32 %30, 8
+  %43 = add nuw nsw i32 %42, %41
+  %44 = load i8, ptr %2, align 1
+  switch i8 %44, label %51 [
+    i8 59, label %56
+    i8 44, label %57
+    i8 0, label %45
+    i8 43, label %45
+    i8 51, label %45
+    i8 60, label %45
+  ]
+
+45:                                               ; preds = %36, %36, %36, %36
+  %46 = sub i32 %43, %6
+  %47 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %46, ptr noundef nonnull %2, i32 noundef 2)
+  %48 = icmp slt i64 %47, 0
+  br i1 %48, label %57, label %49
+
+49:                                               ; preds = %45
+  %50 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @ipv6_hdrlen_offset.____fmt.6, i32 noundef 18)
+  br label %59
+
+51:                                               ; preds = %36, %23, %13, %1
+  %52 = phi i8 [ undef, %1 ], [ %18, %13 ], [ %31, %23 ], [ %44, %36 ]
+  %53 = phi i32 [ 40, %1 ], [ %17, %13 ], [ %30, %23 ], [ %43, %36 ]
+  %54 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @ipv6_hdrlen_offset.____fmt, i32 noundef 17, i32 noundef 0, i32 noundef %53)
+  %55 = icmp ne i8 %52, 58
+  br label %59
+
+56:                                               ; preds = %36, %23, %13, %1
+  br label %59
+
+57:                                               ; preds = %45, %36, %32, %23, %19, %13, %1, %9
+  %58 = phi i32 [ -134, %9 ], [ -157, %1 ], [ -157, %13 ], [ -134, %19 ], [ -157, %23 ], [ -134, %32 ], [ -157, %36 ], [ -134, %45 ]
+  br label %59
+
+59:                                               ; preds = %57, %56, %51, %49
+  %60 = phi i1 [ %55, %51 ], [ undef, %49 ], [ undef, %56 ], [ undef, %57 ]
+  %61 = phi i32 [ %53, %51 ], [ -156, %49 ], [ -156, %56 ], [ %58, %57 ]
+  call void @llvm.lifetime.end.p0(i64 2, ptr nonnull %2)
+  %62 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.2, i32 noundef 24)
+  %63 = icmp slt i32 %61, 0
+  %64 = or i1 %63, %60
+  br i1 %64, label %65, label %67
+
+65:                                               ; preds = %59
+  %66 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.3, i32 noundef 5)
+  br label %77
+
+67:                                               ; preds = %59
+  %68 = call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76)
+  %69 = zext nneg i32 %61 to i64
+  %70 = getelementptr inbounds nuw i8, ptr %68, i64 %69
+  %71 = load i8, ptr %70, align 4
+  %72 = icmp eq i8 %71, -121
+  br i1 %72, label %75, label %73
+
+73:                                               ; preds = %67
+  %74 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.4, i32 noundef 5)
+  br label %77
+
+75:                                               ; preds = %67
+  %76 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.5, i32 noundef 5)
+  br label %77
+
+77:                                               ; preds = %65, %73, %75
+  %78 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt.1, i32 noundef 4)
+  ret i32 0
+}
diff --git a/llvm/test/CodeGen/BPF/undef-sroa.ll b/llvm/test/CodeGen/BPF/undef-sroa.ll
new file mode 100644
index 0000000000000..73eeaf6935c8c
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/undef-sroa.ll
@@ -0,0 +1,14 @@
+; RUN: opt -S -passes='sroa' %s -o %t1
+; RUN: opt --bpf-check-undef-ir -S -mtriple=bpf-pc-linux %t1 >& %t2
+; RUN: cat %t2 | FileCheck -check-prefixes=CHECK %s
+
+define dso_local i32 @foo() {
+  %1 = alloca [2 x i32], align 4
+  call void @llvm.lifetime.start.p0(i64 8, ptr %1)
+  %2 = getelementptr inbounds [2 x i32], ptr %1, i64 0, i64 1
+  %3 = load i32, ptr %2, align 4
+  call void @llvm.lifetime.end.p0(i64 8, ptr %1)
+  ret i32 %3
+}
+; CHECK: return undefined value in func foo, due to uninitialized variable?
+; CHECK: ret i32 undef

>From a5811fb985c046666d594f3c1a061a267717d88e Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Fri, 14 Feb 2025 08:11:20 -0800
Subject: [PATCH 2/4] Do not do checking for returning undef value

Upstream does not like to check undef value and clang-format will
fail due to this. Let us remove checking for returning undef value.
A related test is also removed.
---
 llvm/lib/Target/BPF/BPFCheckUndefIR.cpp | 24 ++----------------------
 llvm/test/CodeGen/BPF/undef-sroa.ll     | 14 --------------
 2 files changed, 2 insertions(+), 36 deletions(-)
 delete mode 100644 llvm/test/CodeGen/BPF/undef-sroa.ll

diff --git a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
index d7bbadba4663d..239aad112f1cf 100644
--- a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
+++ b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Check 'undef' and 'unreachable' IRs and issue proper warnings.
+// Check 'unreachable' IRs and issue proper warnings.
 //
 //===----------------------------------------------------------------------===//
 
@@ -34,7 +34,6 @@ class BPFCheckUndefIR final : public ModulePass {
 private:
   void BPFCheckUndefIRImpl(Function &F);
   void BPFCheckInst(Function &F, BasicBlock &BB, Instruction &I);
-  void HandleReturnInsn(Function &F, ReturnInst *I);
   void HandleUnreachableInsn(Function &F, BasicBlock &BB, Instruction &I);
 };
 } // End anonymous namespace
@@ -45,17 +44,6 @@ INITIALIZE_PASS(BPFCheckUndefIR, DEBUG_TYPE, "BPF Check Undef IRs", false,
 
 ModulePass *llvm::createBPFCheckUndefIR() { return new BPFCheckUndefIR(); }
 
-void BPFCheckUndefIR::HandleReturnInsn(Function &F, ReturnInst *I) {
-  Value *RetValue = I->getReturnValue();
-  // PoisonValue is a special UndefValue where compiler intentionally to
-  // poisons a value since it shouldn't be used.
-  if (!RetValue || isa<PoisonValue>(RetValue) || !isa<UndefValue>(RetValue))
-    return;
-
-  dbgs() << "WARNING: return undefined value in func " << F.getName()
-         << ", due to uninitialized variable?\n";
-}
-
 void BPFCheckUndefIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
                                             Instruction &I) {
   // LLVM may create a switch statement with default to a 'unreachable' basic
@@ -87,16 +75,8 @@ void BPFCheckUndefIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
 
 void BPFCheckUndefIR::BPFCheckInst(Function &F, BasicBlock &BB,
                                    Instruction &I) {
-  switch (I.getOpcode()) {
-  case Instruction::Ret:
-    HandleReturnInsn(F, cast<ReturnInst>(&I));
-    break;
-  case Instruction::Unreachable:
+  if (I.getOpcode() == Instruction::Unreachable)
     HandleUnreachableInsn(F, BB, I);
-    break;
-  default:
-    break;
-  }
 }
 
 void BPFCheckUndefIR::BPFCheckUndefIRImpl(Function &F) {
diff --git a/llvm/test/CodeGen/BPF/undef-sroa.ll b/llvm/test/CodeGen/BPF/undef-sroa.ll
deleted file mode 100644
index 73eeaf6935c8c..0000000000000
--- a/llvm/test/CodeGen/BPF/undef-sroa.ll
+++ /dev/null
@@ -1,14 +0,0 @@
-; RUN: opt -S -passes='sroa' %s -o %t1
-; RUN: opt --bpf-check-undef-ir -S -mtriple=bpf-pc-linux %t1 >& %t2
-; RUN: cat %t2 | FileCheck -check-prefixes=CHECK %s
-
-define dso_local i32 @foo() {
-  %1 = alloca [2 x i32], align 4
-  call void @llvm.lifetime.start.p0(i64 8, ptr %1)
-  %2 = getelementptr inbounds [2 x i32], ptr %1, i64 0, i64 1
-  %3 = load i32, ptr %2, align 4
-  call void @llvm.lifetime.end.p0(i64 8, ptr %1)
-  ret i32 %3
-}
-; CHECK: return undefined value in func foo, due to uninitialized variable?
-; CHECK: ret i32 undef

>From fcbcd8e7c16810796e418fc89a3b8521080aed87 Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Sat, 15 Feb 2025 08:08:30 -0800
Subject: [PATCH 3/4] Remove undef-sccp.ll and use DiagnosticInfo for warning

The test undef-sccp.ll still uses 'undef' in the IR and clang-format
complains it. In this particular case, 'undef' is generated in sroa
and it needs a lot of other passes to reach sccp. So let us remove
this test. The test itself can be accessed in
  https://gist.github.com/yonghong-song/11be8603ad9422f418f60b41beded047
which can be tested in llvm/test/CodeGen/BPF directory.

DiagnosticInfo() is the recommended interface for warnings comparing to
dbgs().
---
 llvm/lib/Target/BPF/BPFCheckUndefIR.cpp |   8 +-
 llvm/test/CodeGen/BPF/undef-sccp.ll     | 172 ------------------------
 2 files changed, 6 insertions(+), 174 deletions(-)
 delete mode 100644 llvm/test/CodeGen/BPF/undef-sccp.ll

diff --git a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
index 239aad112f1cf..5653959eb314d 100644
--- a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
+++ b/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
@@ -12,6 +12,7 @@
 
 #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"
@@ -69,8 +70,11 @@ void BPFCheckUndefIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
       return;
   }
 
-  dbgs() << "WARNING: unreachable in func " << F.getName()
-         << ", due to uninitialized variable?\n";
+  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,
diff --git a/llvm/test/CodeGen/BPF/undef-sccp.ll b/llvm/test/CodeGen/BPF/undef-sccp.ll
deleted file mode 100644
index 1cc6950fe304d..0000000000000
--- a/llvm/test/CodeGen/BPF/undef-sccp.ll
+++ /dev/null
@@ -1,172 +0,0 @@
-; RUN: opt -S -passes='sccp' %s -o %t1
-; RUN: opt --bpf-check-undef-ir -S -mtriple=bpf-pc-linux %t1 >& %t2
-; RUN: cat %t2 | FileCheck -check-prefixes=CHECK %s
-
-%union.v6addr = type { %struct.anon.1 }
-%struct.anon.1 = type { i64, i64 }
-%union.macaddr = type { %struct.anon }
-%struct.anon = type { i32, i16 }
-%struct.icmp6hdr = type { i8, i8, i16, %union.anon }
-%union.anon = type { [1 x i32] }
-%struct.ipv6_opt_hdr = type { i8, i8 }
-
- at repro.____fmt = internal constant [6 x i8] c"Start\00", align 1
- at repro.____fmt.1 = internal constant [4 x i8] c"End\00", align 1
- at __packed = dso_local global %union.v6addr zeroinitializer, align 8
- at icmp6_ndisc_validate.____fmt = internal constant [23 x i8] c"pre ipv6_hdrlen_offset\00", align 1
- at icmp6_ndisc_validate.____fmt.2 = internal constant [24 x i8] c"post ipv6_hdrlen_offset\00", align 1
- at icmp6_ndisc_validate.____fmt.3 = internal constant [5 x i8] c"KO 1\00", align 1
- at icmp6_ndisc_validate.____fmt.4 = internal constant [5 x i8] c"KO 2\00", align 1
- at icmp6_ndisc_validate.____fmt.5 = internal constant [5 x i8] c"ACK \00", align 1
- at ipv6_hdrlen_offset.____fmt = internal constant [17 x i8] c"OKOK %d, len: %d\00", align 1
- at ipv6_hdrlen_offset.____fmt.6 = internal constant [18 x i8] c"KO INVALID EXTHDR\00", align 1
- at llvm.compiler.used = appending global [1 x ptr] [ptr @repro], section "llvm.metadata"
-
-define dso_local i32 @repro(ptr noundef %0) section "classifier" {
-  %2 = alloca %struct.ipv6_opt_hdr, align 8
-  %3 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt, i32 noundef 6)
-  %4 = tail call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76)
-  %5 = ptrtoint ptr %4 to i64
-  %6 = trunc i64 %5 to i32
-  %7 = tail call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt, i32 noundef 23)
-  call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %2)
-  %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
-  switch i8 undef, label %51 [
-    i8 59, label %56
-    i8 44, label %57
-    i8 0, label %9
-    i8 43, label %9
-    i8 51, label %9
-    i8 60, label %9
-  ]
-
-; CHECK:       unreachable in func repro, due to uninitialized variable?
-; CHECK:       %8 = getelementptr inbounds nuw i8, ptr %2, i64 1
-; CHECK-NEXT:  unreachable
-
-9:                                                ; preds = %1, %1, %1, %1
-  %10 = sub i32 40, %6
-  %11 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %10, ptr noundef nonnull %2, i32 noundef 2)
-  %12 = icmp slt i64 %11, 0
-  br i1 %12, label %57, label %13
-
-13:                                               ; preds = %9
-  %14 = load i8, ptr %8, align 1
-  %15 = zext i8 %14 to i32
-  %16 = shl nuw nsw i32 %15, 3
-  %17 = add nuw nsw i32 48, %16
-  %18 = load i8, ptr %2, align 1
-  switch i8 %18, label %51 [
-    i8 59, label %56
-    i8 44, label %57
-    i8 0, label %19
-    i8 43, label %19
-    i8 51, label %19
-    i8 60, label %19
-  ]
-
-19:                                               ; preds = %13, %13, %13, %13
-  %20 = sub i32 %17, %6
-  %21 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %20, ptr noundef nonnull %2, i32 noundef 2)
-  %22 = icmp slt i64 %21, 0
-  br i1 %22, label %57, label %23
-
-23:                                               ; preds = %19
-  %24 = icmp eq i8 %18, 51
-  %25 = load i8, ptr %8, align 1
-  %26 = zext i8 %25 to i32
-  %27 = select i1 %24, i32 2, i32 3
-  %28 = shl nuw nsw i32 %26, %27
-  %29 = add nuw nsw i32 %17, 8
-  %30 = add nuw nsw i32 %29, %28
-  %31 = load i8, ptr %2, align 1
-  switch i8 %31, label %51 [
-    i8 59, label %56
-    i8 44, label %57
-    i8 0, label %32
-    i8 43, label %32
-    i8 51, label %32
-    i8 60, label %32
-  ]
-
-32:                                               ; preds = %23, %23, %23, %23
-  %33 = sub i32 %30, %6
-  %34 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %33, ptr noundef nonnull %2, i32 noundef 2)
-  %35 = icmp slt i64 %34, 0
-  br i1 %35, label %57, label %36
-
-36:                                               ; preds = %32
-  %37 = icmp eq i8 %31, 51
-  %38 = load i8, ptr %8, align 1
-  %39 = zext i8 %38 to i32
-  %40 = select i1 %37, i32 2, i32 3
-  %41 = shl nuw nsw i32 %39, %40
-  %42 = add nuw nsw i32 %30, 8
-  %43 = add nuw nsw i32 %42, %41
-  %44 = load i8, ptr %2, align 1
-  switch i8 %44, label %51 [
-    i8 59, label %56
-    i8 44, label %57
-    i8 0, label %45
-    i8 43, label %45
-    i8 51, label %45
-    i8 60, label %45
-  ]
-
-45:                                               ; preds = %36, %36, %36, %36
-  %46 = sub i32 %43, %6
-  %47 = call i64 inttoptr (i64 26 to ptr)(ptr noundef %0, i32 noundef %46, ptr noundef nonnull %2, i32 noundef 2)
-  %48 = icmp slt i64 %47, 0
-  br i1 %48, label %57, label %49
-
-49:                                               ; preds = %45
-  %50 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @ipv6_hdrlen_offset.____fmt.6, i32 noundef 18)
-  br label %59
-
-51:                                               ; preds = %36, %23, %13, %1
-  %52 = phi i8 [ undef, %1 ], [ %18, %13 ], [ %31, %23 ], [ %44, %36 ]
-  %53 = phi i32 [ 40, %1 ], [ %17, %13 ], [ %30, %23 ], [ %43, %36 ]
-  %54 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @ipv6_hdrlen_offset.____fmt, i32 noundef 17, i32 noundef 0, i32 noundef %53)
-  %55 = icmp ne i8 %52, 58
-  br label %59
-
-56:                                               ; preds = %36, %23, %13, %1
-  br label %59
-
-57:                                               ; preds = %45, %36, %32, %23, %19, %13, %1, %9
-  %58 = phi i32 [ -134, %9 ], [ -157, %1 ], [ -157, %13 ], [ -134, %19 ], [ -157, %23 ], [ -134, %32 ], [ -157, %36 ], [ -134, %45 ]
-  br label %59
-
-59:                                               ; preds = %57, %56, %51, %49
-  %60 = phi i1 [ %55, %51 ], [ undef, %49 ], [ undef, %56 ], [ undef, %57 ]
-  %61 = phi i32 [ %53, %51 ], [ -156, %49 ], [ -156, %56 ], [ %58, %57 ]
-  call void @llvm.lifetime.end.p0(i64 2, ptr nonnull %2)
-  %62 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.2, i32 noundef 24)
-  %63 = icmp slt i32 %61, 0
-  %64 = or i1 %63, %60
-  br i1 %64, label %65, label %67
-
-65:                                               ; preds = %59
-  %66 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.3, i32 noundef 5)
-  br label %77
-
-67:                                               ; preds = %59
-  %68 = call ptr asm sideeffect "$0 = *(u32 *)($1 + $2)", "=r,r,i"(ptr %0, i64 76)
-  %69 = zext nneg i32 %61 to i64
-  %70 = getelementptr inbounds nuw i8, ptr %68, i64 %69
-  %71 = load i8, ptr %70, align 4
-  %72 = icmp eq i8 %71, -121
-  br i1 %72, label %75, label %73
-
-73:                                               ; preds = %67
-  %74 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.4, i32 noundef 5)
-  br label %77
-
-75:                                               ; preds = %67
-  %76 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @icmp6_ndisc_validate.____fmt.5, i32 noundef 5)
-  br label %77
-
-77:                                               ; preds = %65, %73, %75
-  %78 = call i64 (ptr, i32, ...) inttoptr (i64 6 to ptr)(ptr noundef nonnull @repro.____fmt.1, i32 noundef 4)
-  ret i32 0
-}

>From 1c19baed253b0deef8c64715b946f14fab245a5e Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Fri, 21 Feb 2025 08:47:08 -0800
Subject: [PATCH 4/4] 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.
---
 llvm/lib/Target/BPF/BPF.h                     |  4 +-
 ...kUndefIR.cpp => BPFCheckUnreachableIR.cpp} | 48 +++++++++++--------
 llvm/lib/Target/BPF/BPFTargetMachine.cpp      |  4 +-
 llvm/lib/Target/BPF/CMakeLists.txt            |  2 +-
 .../BPF/naked-fn-with-frame-pointer.ll        |  2 +-
 llvm/test/CodeGen/BPF/store_imm.ll            | 12 ++---
 6 files changed, 41 insertions(+), 31 deletions(-)
 rename llvm/lib/Target/BPF/{BPFCheckUndefIR.cpp => BPFCheckUnreachableIR.cpp} (61%)

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/BPFCheckUnreachableIR.cpp
similarity index 61%
rename from llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
rename to llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp
index 5653959eb314d..ef8bc19322abb 100644
--- a/llvm/lib/Target/BPF/BPFCheckUndefIR.cpp
+++ b/llvm/lib/Target/BPF/BPFCheckUnreachableIR.cpp
@@ -1,4 +1,4 @@
-//===---------------- BPFAdjustOpt.cpp - Adjust Optimization --------------===//
+//===--------- 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.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Check 'unreachable' IRs and issue proper warnings.
+// Check 'unreachable' IRs and issue proper errors.
 //
 //===----------------------------------------------------------------------===//
 
@@ -19,34 +19,41 @@
 #include "llvm/IR/Value.h"
 #include "llvm/Pass.h"
 
-#define DEBUG_TYPE "bpf-check-undef-ir"
+#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 BPFCheckUndefIR final : public ModulePass {
+class BPFCheckUnreachableIR final : public ModulePass {
   bool runOnModule(Module &F) override;
 
 public:
   static char ID;
-  BPFCheckUndefIR() : ModulePass(ID) {}
+  BPFCheckUnreachableIR() : ModulePass(ID) {}
 
 private:
-  void BPFCheckUndefIRImpl(Function &F);
+  void BPFCheckUnreachableIRImpl(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)
+char BPFCheckUnreachableIR::ID = 0;
+INITIALIZE_PASS(BPFCheckUnreachableIR, DEBUG_TYPE, "BPF Check Unreachable IRs",
+                false, false)
 
-ModulePass *llvm::createBPFCheckUndefIR() { return new BPFCheckUndefIR(); }
+ModulePass *llvm::createBPFCheckUnreachableIR() {
+  return new BPFCheckUnreachableIR();
+}
 
-void BPFCheckUndefIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
-                                            Instruction &I) {
+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;
@@ -73,17 +80,18 @@ void BPFCheckUndefIR::HandleUnreachableInsn(Function &F, BasicBlock &BB,
   F.getContext().diagnose(
       DiagnosticInfoGeneric(Twine("unreachable in func ")
                                 .concat(F.getName())
-                                .concat(", due to uninitialized variable?"),
-                            DS_Warning));
+                                .concat(", due to uninitialized variable?")
+                                .concat(" try -Wuninitialized?"),
+                            DS_Error));
 }
 
-void BPFCheckUndefIR::BPFCheckInst(Function &F, BasicBlock &BB,
-                                   Instruction &I) {
+void BPFCheckUnreachableIR::BPFCheckInst(Function &F, BasicBlock &BB,
+                                         Instruction &I) {
   if (I.getOpcode() == Instruction::Unreachable)
     HandleUnreachableInsn(F, BB, I);
 }
 
-void BPFCheckUndefIR::BPFCheckUndefIRImpl(Function &F) {
+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))
@@ -95,8 +103,10 @@ void BPFCheckUndefIR::BPFCheckUndefIRImpl(Function &F) {
   }
 }
 
-bool BPFCheckUndefIR::runOnModule(Module &M) {
+bool BPFCheckUnreachableIR::runOnModule(Module &M) {
+  if (DisableCheckUnreachableIR)
+    return false;
   for (Function &F : M)
-    BPFCheckUndefIRImpl(F);
+    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
 }



More information about the llvm-commits mailing list