[llvm] [InstCombine] Emit fatal error on void to non-void conversion (PR #96574)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 24 16:03:16 PDT 2024
https://github.com/yozhu created https://github.com/llvm/llvm-project/pull/96574
It is undefined behavior for a call instruction to expect a non-void return
value while the callee returns void. Instead of continuing optimization, we
now emit a fatal error to report such cases.
>From 21ffcfec918f803a298b9d3816911e494b8e1c5c Mon Sep 17 00:00:00 2001
From: YongKang Zhu <yongzhu at fb.com>
Date: Mon, 24 Jun 2024 15:51:22 -0700
Subject: [PATCH] [InstCombine] Emit fatal error on call instruction that need
a void to non-void return value conversion
---
.../InstCombine/InstCombineCalls.cpp | 20 +++++-
.../X86/Inputs/index-const-prop-cache-foo.ll | 4 +-
.../InstCombine/2008-01-06-VoidCast.ll | 20 ------
.../WholeProgramDevirt/branch-funnel.ll | 64 +++++++++----------
4 files changed, 51 insertions(+), 57 deletions(-)
delete mode 100644 llvm/test/Transforms/InstCombine/2008-01-06-VoidCast.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 436cdbff75669..b15289d55bf17 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -72,6 +72,7 @@
#include <cassert>
#include <cstdint>
#include <optional>
+#include <sstream>
#include <utility>
#include <vector>
@@ -4020,10 +4021,23 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
if (Callee->isDeclaration())
return false; // Cannot transform this return value.
- if (!Caller->use_empty() &&
- // void -> non-void is handled specially
- !NewRetTy->isVoidTy())
+ if (!Caller->use_empty()) {
+ if (NewRetTy->isVoidTy()) {
+ DebugLoc DL = Caller->getDebugLoc();
+ const DILocation *DIL = DL;
+ std::ostringstream ErrMsg;
+ if (DIL)
+ ErrMsg << DIL->getFilename().str() << ":" << DIL->getLine();
+ else
+ ErrMsg << Caller->getFunction()->getName().str();
+ ErrMsg
+ << ": contains a call to " << Callee->getName().str()
+ << ", where a non-void return value is expected but the callee "
+ "returns void\n";
+ report_fatal_error(StringRef(ErrMsg.str()));
+ }
return false; // Cannot transform this return value.
+ }
}
if (!CallerPAL.isEmpty() && !Caller->use_empty()) {
diff --git a/llvm/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll b/llvm/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll
index 58fb47f947c55..172a42a7b5b35 100644
--- a/llvm/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll
+++ b/llvm/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll
@@ -10,10 +10,10 @@ define i32 @foo() local_unnamed_addr {
}
; Function Attrs: nounwind ssp uwtable
-define void @bar() local_unnamed_addr {
+define i32 @bar() local_unnamed_addr {
%1 = tail call i32 @rand()
store i32 %1, ptr @gFoo, align 4
- ret void
+ ret i32 %1
}
declare i32 @rand() local_unnamed_addr
diff --git a/llvm/test/Transforms/InstCombine/2008-01-06-VoidCast.ll b/llvm/test/Transforms/InstCombine/2008-01-06-VoidCast.ll
deleted file mode 100644
index 2fbdd802b46b8..0000000000000
--- a/llvm/test/Transforms/InstCombine/2008-01-06-VoidCast.ll
+++ /dev/null
@@ -1,20 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
-; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-
-define void @f(i16 %y) {
-; CHECK-LABEL: define {{[^@]+}}@f
-; CHECK-SAME: (i16 [[Y:%.*]]) {
-; CHECK-NEXT: ret void
-;
- ret void
-}
-
-define i32 @g(i32 %y) {
-; CHECK-LABEL: define {{[^@]+}}@g
-; CHECK-SAME: (i32 [[Y:%.*]]) {
-; CHECK-NEXT: [[X:%.*]] = call i32 @f(i32 [[Y]])
-; CHECK-NEXT: ret i32 [[X]]
-;
- %x = call i32 @f( i32 %y )
- ret i32 %x
-}
diff --git a/llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll b/llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll
index 0b1023eee2732..fd339f5f58b25 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/branch-funnel.ll
@@ -157,30 +157,30 @@ declare ptr @llvm.load.relative.i32(ptr, i32)
@vt4_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_2 to i64), i64 ptrtoint (ptr @vt4_2_rv to i64)) to i32)], !type !8
-; CHECK-LABEL: define i32 @fn1
+; CHECK-LABEL: define noundef i32 @fn1
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn1(ptr %obj) #0 {
+define noundef i32 @fn1(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr %vtable
; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn1_rv
+; CHECK-LABEL: define noundef i32 @fn1_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn1_rv(ptr %obj) #0 {
+define noundef i32 @fn1_rv(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
; CHECK-LABEL: define i32 @fn2
@@ -207,78 +207,78 @@ define i32 @fn2_rv(ptr %obj) #0 {
ret i32 %result
}
-; CHECK-LABEL: define i32 @fn3
+; CHECK-LABEL: define noundef i32 @fn3
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn3(ptr %obj) #0 {
+define noundef i32 @fn3(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !4)
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr %vtable
; RETP: call i32 @branch_funnel(ptr
; NORETP: call i32 %
- %result = call i32 %fptr(ptr %obj, i32 1)
- ret i32 %result
+ call i32 %fptr(ptr %obj, i32 1)
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn3_rv
+; CHECK-LABEL: define noundef i32 @fn3_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn3_rv(ptr %obj) #0 {
+define noundef i32 @fn3_rv(ptr %obj) #0 {
%vtable = load ptr, ptr %obj
%p = call i1 @llvm.type.test(ptr %vtable, metadata !9)
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
; RETP: call i32 @branch_funnel.1(ptr
; NORETP: call i32 %
- %result = call i32 %fptr(ptr %obj, i32 1)
- ret i32 %result
+ call i32 %fptr(ptr %obj, i32 1)
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn4
+; CHECK-LABEL: define noundef i32 @fn4
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn4(ptr %obj) #0 {
+define noundef i32 @fn4(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr @vt1_1
; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn4_cpy
+; CHECK-LABEL: define noundef i32 @fn4_cpy
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn4_cpy(ptr %obj) #0 {
+define noundef i32 @fn4_cpy(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptr = load ptr, ptr @vt1_1
; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn4_rv
+; CHECK-LABEL: define noundef i32 @fn4_rv
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn4_rv(ptr %obj) #0 {
+define noundef i32 @fn4_rv(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
-; CHECK-LABEL: define i32 @fn4_rv_cpy
+; CHECK-LABEL: define noundef i32 @fn4_rv_cpy
; CHECK-NOT: call void (...) @llvm.icall.branch.funnel
-define i32 @fn4_rv_cpy(ptr %obj) #0 {
+define noundef i32 @fn4_rv_cpy(ptr %obj) #0 {
%p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv")
call void @llvm.assume(i1 %p)
%fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0)
; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1)
- %result = call i32 %fptr(ptr %obj, i32 1)
+ call i32 %fptr(ptr %obj, i32 1)
; NORETP: call i32 %
- ret i32 %result
+ ret i32 0
}
; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(ptr nest %0, ...)
More information about the llvm-commits
mailing list