[llvm] 7c15144 - [SDAG] emit error when `llvm.type.checked.load` is not lowered (#208058)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 01:58:37 PDT 2026


Author: Folkert de Vries
Date: 2026-07-14T10:58:33+02:00
New Revision: 7c151447bc8abceefa3be9e5f1b27b83803d77af

URL: https://github.com/llvm/llvm-project/commit/7c151447bc8abceefa3be9e5f1b27b83803d77af
DIFF: https://github.com/llvm/llvm-project/commit/7c151447bc8abceefa3be9e5f1b27b83803d77af.diff

LOG: [SDAG] emit error when `llvm.type.checked.load` is not lowered (#208058)

Fixes https://github.com/llvm/llvm-project/issues/164663

In rust we can enable devirtualization and LTO on a build that actually
builds a library and hence LTO does not really run. That means typed
loads are emitted, but they are not lowered (or cleaned up), which made
us hit an ICE. Giving a slightly better error message, analogous to the
existing one for `Intrinsic::type_test`, seems nice.

I'm putting this together based on
https://github.com/llvm/llvm-project/pull/179249 and
https://github.com/llvm/llvm-project/issues/164663#issuecomment-3433581033.

Added: 
    llvm/test/CodeGen/X86/type-tests-must-be-lowered.ll

Modified: 
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Removed: 
    llvm/test/CodeGen/X86/pr142937.ll


################################################################################
diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 98c91e65b4752..0f6bd53cafdd8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1814,6 +1814,19 @@ SDValue SelectionDAGBuilder::getValue(const Value *V) {
   return Val;
 }
 
+void SelectionDAGBuilder::setValueToPoison(const Value *V, const SDLoc &dl) {
+  if (V->getType()->isVoidTy())
+    return;
+
+  SmallVector<EVT, 4> ValueVTs;
+  ComputeValueVTs(DAG.getTargetLoweringInfo(), DAG.getDataLayout(),
+                  V->getType(), ValueVTs);
+  SmallVector<SDValue, 4> Results;
+  for (EVT VT : ValueVTs)
+    Results.push_back(DAG.getPOISON(VT));
+  setValue(V, DAG.getMergeValues(Results, dl));
+}
+
 /// getNonRegisterValue - Return an SDValue for the given Value, but
 /// don't look in FuncInfo.ValueMap for a virtual register.
 SDValue SelectionDAGBuilder::getNonRegisterValue(const Value *V) {
@@ -5566,15 +5579,7 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I,
     if (HasChain && !OnlyLoad)
       DAG.setRoot(getRoot());
 
-    if (!I.getType()->isVoidTy()) {
-      SmallVector<EVT, 4> ValueVTs;
-      ComputeValueVTs(DAG.getTargetLoweringInfo(), DAG.getDataLayout(),
-                      I.getType(), ValueVTs);
-      SmallVector<SDValue, 4> Results;
-      for (EVT VT : ValueVTs)
-        Results.push_back(DAG.getPOISON(VT));
-      setValue(&I, DAG.getMergeValues(Results, DL));
-    }
+    setValueToPoison(&I, DL);
     return;
   }
 
@@ -7729,9 +7734,24 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
 
   case Intrinsic::type_test:
   case Intrinsic::public_type_test:
-    reportFatalUsageError("llvm.type.test intrinsic must be lowered by the "
-                          "LowerTypeTests pass before code generation");
+  case Intrinsic::type_checked_load:
+  case Intrinsic::type_checked_load_relative: {
+    // These intrinsics are expected to be lowered by the LowerTypeTests pass
+    // before code generation. Surviving until here usually indicates a
+    // misconfiguration, for instance when devirtualization is enabled but LTO
+    // does not actually run.
+    DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+        *I.getFunction(),
+        Intrinsic::getBaseName(Intrinsic) +
+            " intrinsic must be lowered by the LowerTypeTests pass "
+            "before code generation",
+        sdl.getDebugLoc()));
+
+    // Lower the result to poison so that compilation can continue and collect
+    // any further diagnostics.
+    setValueToPoison(&I, sdl);
     return;
+  }
 
   case Intrinsic::assume:
   case Intrinsic::experimental_noalias_scope_decl:

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 21aac333a73cd..6c7711af078f0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -397,6 +397,8 @@ class SelectionDAGBuilder {
     N = NewN;
   }
 
+  void setValueToPoison(const Value *V, const SDLoc &dl);
+
   bool shouldKeepJumpConditionsTogether(
       const FunctionLoweringInfo &FuncInfo, const CondBrInst &I,
       Instruction::BinaryOps Opc, const Value *Lhs, const Value *Rhs,

diff  --git a/llvm/test/CodeGen/X86/pr142937.ll b/llvm/test/CodeGen/X86/pr142937.ll
deleted file mode 100644
index 675bb9ea52189..0000000000000
--- a/llvm/test/CodeGen/X86/pr142937.ll
+++ /dev/null
@@ -1,33 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: not llc %s -mtriple=i686-- -O0 -filetype=null 2>&1 | FileCheck %s
-; RUN: not llc %s -mtriple=x86_64-- -O0 -filetype=null 2>&1 | FileCheck %s
-
-; CHECK: must be lowered by the LowerTypeTests pass
-
-define void @public_type_test() {
-bb:
-  %call = call i1 @llvm.public.type.test(ptr null, metadata !"typeinfo")
-  br label %bb1
-
-bb1:
-  call void @llvm.assume(i1 %call)
-  ret void
-}
-
-define void @type_test() {
-bb:
-  %call = tail call i1 @llvm.type.test(ptr null, metadata !"typeinfo")
-  br i1 %call, label %bb2, label %bb1
-
-bb1:
-  tail call void @llvm.ubsantrap(i8 2)
-  unreachable
-
-bb2:
-  ret void
-}
-
-declare i1 @llvm.public.type.test(ptr, metadata)
-declare void @llvm.assume(i1 noundef)
-declare i1 @llvm.type.test(ptr, metadata)
-declare void @llvm.ubsantrap(i8 immarg)

diff  --git a/llvm/test/CodeGen/X86/type-tests-must-be-lowered.ll b/llvm/test/CodeGen/X86/type-tests-must-be-lowered.ll
new file mode 100644
index 0000000000000..2b49ee1826a36
--- /dev/null
+++ b/llvm/test/CodeGen/X86/type-tests-must-be-lowered.ll
@@ -0,0 +1,46 @@
+; RUN: not llc %s -mtriple=i686-- -O0 -filetype=null 2>&1 | FileCheck %s
+; RUN: not llc %s -mtriple=x86_64-- -O0 -filetype=null 2>&1 | FileCheck %s
+
+; The llvm.type.test, llvm.public.type.test, llvm.type.checked.load and
+; llvm.type.checked.load.relative intrinsics are expected to be lowered by the
+; LowerTypeTests pass before code generation. If one survives, emit a clean
+; diagnostic instead of crashing (see issues #142937 and #164663).
+
+; CHECK: type.test intrinsic must be lowered by the LowerTypeTests pass before code generation
+define void @type_test() {
+bb:
+  %call = tail call i1 @llvm.type.test(ptr null, metadata !"typeinfo")
+  br i1 %call, label %bb2, label %bb1
+
+bb1:
+  tail call void @llvm.ubsantrap(i8 2)
+  unreachable
+
+bb2:
+  ret void
+}
+
+; CHECK: public.type.test intrinsic must be lowered by the LowerTypeTests pass before code generation
+define void @public_type_test() {
+bb:
+  %call = call i1 @llvm.public.type.test(ptr null, metadata !"typeinfo")
+  br label %bb1
+
+bb1:
+  call void @llvm.assume(i1 %call)
+  ret void
+}
+
+; CHECK: type.checked.load intrinsic must be lowered by the LowerTypeTests pass before code generation
+define i1 @type_checked_load(ptr %vtable) {
+  %pair = call { ptr, i1 } @llvm.type.checked.load(ptr %vtable, i32 4, metadata !"typeid")
+  %ok = extractvalue { ptr, i1 } %pair, 1
+  ret i1 %ok
+}
+
+; CHECK: type.checked.load.relative intrinsic must be lowered by the LowerTypeTests pass before code generation
+define i1 @type_checked_load_relative(ptr %vtable) {
+  %pair = call { ptr, i1 } @llvm.type.checked.load.relative(ptr %vtable, i32 4, metadata !"typeid")
+  %ok = extractvalue { ptr, i1 } %pair, 1
+  ret i1 %ok
+}


        


More information about the llvm-commits mailing list