From 56d228a14e3631de157ae98dd61d21193e4502d5 Mon Sep 17 00:00:00 2001 From: Juneyoung Lee Date: Tue, 23 Feb 2021 11:46:59 +0900 Subject: [PATCH] [SimplifyCFG] Update passingValueIsAlwaysUndefined to check more attributes This is a simple patch to update SimplifyCFG's passingValueIsAlwaysUndefined to inspect more attributes. A new function `CallBase::isPassingUndefUB` checks attributes that imply noundef. Reviewed By: spatel Differential Revision: https://reviews.llvm.org/D97244 --- llvm/include/llvm/IR/InstrTypes.h | 11 +++++++++++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 6 +++--- llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll | 10 ++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h index 01a51ed..6066889 100644 --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1653,6 +1653,17 @@ public: paramHasAttr(ArgNo, Attribute::Preallocated); } + /// Determine whether passing undef to this argument is undefined behavior. + /// If passing undef to this argument is UB, passing poison is UB as well + /// because poison is more undefined than undef. + bool isPassingUndefUB(unsigned ArgNo) const { + return paramHasAttr(ArgNo, Attribute::NoUndef) || + // dereferenceable implies noundef. + paramHasAttr(ArgNo, Attribute::Dereferenceable) || + // dereferenceable implies noundef, and null is a well-defined value. + paramHasAttr(ArgNo, Attribute::DereferenceableOrNull); + } + /// Determine if there are is an inalloca argument. Only the last argument can /// have the inalloca attribute. bool hasInAllocaArgument() const { diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index df851c1..30d9daf 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6433,8 +6433,8 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu for (const llvm::Use &Arg : CB->args()) if (Arg == I) { unsigned ArgIdx = CB->getArgOperandNo(&Arg); - if (CB->paramHasAttr(ArgIdx, Attribute::NonNull) && - CB->paramHasAttr(ArgIdx, Attribute::NoUndef)) { + if (CB->isPassingUndefUB(ArgIdx) && + CB->paramHasAttr(ArgIdx, Attribute::NonNull)) { // Passing null to a nonnnull+noundef argument is undefined. return !PtrValueMayBeModified; } @@ -6444,7 +6444,7 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu for (const llvm::Use &Arg : CB->args()) if (Arg == I) { unsigned ArgIdx = CB->getArgOperandNo(&Arg); - if (CB->paramHasAttr(ArgIdx, Attribute::NoUndef)) { + if (CB->isPassingUndefUB(ArgIdx)) { // Passing undef to a noundef argument is undefined. return true; } diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll index af8682d..cdec294 100644 --- a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -234,8 +234,9 @@ else: define void @test9_deref(i1 %X, i8* %Y) { ; CHECK-LABEL: @test9_deref( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]] -; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_deref_arg(i8* [[SPEC_SELECT]]) +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_deref_arg(i8* [[Y:%.*]]) ; CHECK-NEXT: ret void ; entry: @@ -254,8 +255,9 @@ else: define void @test9_deref_or_null(i1 %X, i8* %Y) { ; CHECK-LABEL: @test9_deref_or_null( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]] -; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_deref_or_null_arg(i8* [[SPEC_SELECT]]) +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_deref_or_null_arg(i8* [[Y:%.*]]) ; CHECK-NEXT: ret void ; entry: -- 2.7.4