[InstCombine] Treat passing undef to noundef params as UB

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D133036
This commit is contained in:
Arthur Eubanks 2022-08-31 11:17:10 -07:00
parent 5a231720bc
commit c911befaec
4 changed files with 32 additions and 21 deletions

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -no-opaque-pointers -cl-std=CL2.0 -emit-llvm -o - -triple spir-unknown-unknown %s | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - -triple spir-unknown-unknown %s | FileCheck %s
// RUN: %clang_cc1 -disable-llvm-passes -no-opaque-pointers -cl-std=CL2.0 -emit-llvm -o - -triple spir-unknown-unknown %s | FileCheck %s
// RUN: %clang_cc1 -disable-llvm-passes -no-opaque-pointers -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - -triple spir-unknown-unknown %s | FileCheck %s
typedef short short4 __attribute__((ext_vector_type(4)));
@ -21,18 +21,18 @@ void kernel test1() {
generic int *generic *gengen;
generic int *local *genloc;
generic int *global *genglob;
// CHECK-DAG: call spir_func void @_Z3fooPU3AS1iS0_(i32 addrspace(1)* noundef undef, i32 addrspace(1)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3fooPU3AS1iS0_(i32 addrspace(1)* noundef {{.*}}, i32 addrspace(1)* noundef {{.*}})
foo(a, b);
// CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* noundef undef, i32 addrspace(4)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* noundef {{.*}}, i32 addrspace(4)* noundef {{.*}})
foo(b, c);
// CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* noundef undef, i32 addrspace(4)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3fooPU3AS4iS0_(i32 addrspace(4)* noundef {{.*}}, i32 addrspace(4)* noundef {{.*}})
foo(a, d);
// CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* noundef undef, i32 addrspace(4)* addrspace(4)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* noundef {{.*}}, i32 addrspace(4)* addrspace(4)* noundef {{.*}})
bar(gengen, genloc);
// CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* noundef undef, i32 addrspace(4)* addrspace(4)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3barPU3AS4PU3AS4iS2_(i32 addrspace(4)* addrspace(4)* noundef {{.*}}, i32 addrspace(4)* addrspace(4)* noundef {{.*}})
bar(gengen, genglob);
// CHECK-DAG: call spir_func void @_Z3barPU3AS1PU3AS4iS2_(i32 addrspace(4)* addrspace(1)* noundef undef, i32 addrspace(4)* addrspace(1)* noundef undef)
// CHECK-DAG: call spir_func void @_Z3barPU3AS1PU3AS4iS2_(i32 addrspace(4)* addrspace(1)* noundef {{.*}}, i32 addrspace(4)* addrspace(1)* noundef {{.*}})
bar(genglob, genglob);
}
@ -40,8 +40,8 @@ void kernel test1() {
void kernel test2() {
short4 e0=0;
// CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sss(<4 x i16> noundef zeroinitializer, i16 noundef signext 0, i16 noundef signext 255)
// CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sss(<4 x i16> noundef {{.*}}, i16 noundef signext 0, i16 noundef signext 255)
clamp(e0, 0, 255);
// CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sS_S_(<4 x i16> noundef zeroinitializer, <4 x i16> noundef zeroinitializer, <4 x i16> noundef zeroinitializer)
// CHECK-DAG: call spir_func <4 x i16> @_Z5clampDv4_sS_S_(<4 x i16> noundef {{.*}}, <4 x i16> noundef {{.*}}, <4 x i16> noundef {{.*}})
clamp(e0, e0, e0);
}

View File

@ -2900,6 +2900,15 @@ static IntrinsicInst *findInitTrampoline(Value *Callee) {
return nullptr;
}
static bool callPassesUndefToPassingUndefUBParam(CallBase &Call) {
for (unsigned I = 0; I < Call.arg_size(); ++I) {
if (isa<UndefValue>(Call.getArgOperand(I)) && Call.isPassingUndefUB(I)) {
return true;
}
}
return false;
}
bool InstCombinerImpl::annotateAnyAllocSite(CallBase &Call,
const TargetLibraryInfo *TLI) {
// Note: We only handle cases which can't be driven from generic attributes
@ -3026,9 +3035,11 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
// Calling a null function pointer is undefined if a null address isn't
// dereferenceable.
// Passing undef/poison to any parameter where doing so is UB is undefined (of
// course).
if ((isa<ConstantPointerNull>(Callee) &&
!NullPointerIsDefined(Call.getFunction())) ||
isa<UndefValue>(Callee)) {
isa<UndefValue>(Callee) || callPassesUndefToPassingUndefUBParam(Call)) {
// If Call does not return void then replaceInstUsesWith poison.
// This allows ValueHandlers and custom metadata to adjust itself.
if (!Call.getType()->isVoidTy())

View File

@ -8,7 +8,7 @@ declare void @f(ptr)
define void @test1() {
; CHECK-LABEL: @test1(
; CHECK-NEXT: call void @c(i32 undef)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @c(i32 undef)
@ -17,7 +17,7 @@ define void @test1() {
define void @test2() {
; CHECK-LABEL: @test2(
; CHECK-NEXT: call void @c(i32 poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @c(i32 poison)
@ -26,7 +26,7 @@ define void @test2() {
define void @test3() {
; CHECK-LABEL: @test3(
; CHECK-NEXT: call void @e(i32 noundef undef)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @e(i32 noundef undef)
@ -35,7 +35,7 @@ define void @test3() {
define void @test4() {
; CHECK-LABEL: @test4(
; CHECK-NEXT: call void @e(i32 noundef poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @e(i32 noundef poison)
@ -44,7 +44,7 @@ define void @test4() {
define void @test5() {
; CHECK-LABEL: @test5(
; CHECK-NEXT: call void @d(ptr undef)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @d(ptr undef)
@ -53,7 +53,7 @@ define void @test5() {
define void @test6() {
; CHECK-LABEL: @test6(
; CHECK-NEXT: call void @d(ptr poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @d(ptr poison)
@ -62,7 +62,7 @@ define void @test6() {
define void @test7() {
; CHECK-LABEL: @test7(
; CHECK-NEXT: call void @f(ptr dereferenceable(1) undef)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @f(ptr dereferenceable(1) undef)
@ -71,7 +71,7 @@ define void @test7() {
define void @test8() {
; CHECK-LABEL: @test8(
; CHECK-NEXT: call void @f(ptr dereferenceable(1) poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret void
;
call void @f(ptr dereferenceable(1) poison)

View File

@ -6,7 +6,7 @@ define i32 @test_out_of_bounds(i32 %a, i1 %x, i1 %y) {
; CHECK-LABEL: @test_out_of_bounds(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], 3
; CHECK-NEXT: tail call void @llvm.assume(i1 poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret i32 [[AND1]]
;
entry:
@ -20,7 +20,7 @@ entry:
define i128 @test_non64bit(i128 %a) {
; CHECK-LABEL: @test_non64bit(
; CHECK-NEXT: [[AND1:%.*]] = and i128 [[A:%.*]], 3
; CHECK-NEXT: tail call void @llvm.assume(i1 poison)
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: ret i128 [[AND1]]
;
%and1 = and i128 %a, 3