diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1653,6 +1653,17 @@ 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 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6433,8 +6433,8 @@ 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 @@ 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; }