[llvm] bb0b231 - [InstCombineCalls] Optimize call of bitcast even w/ parameter attributes
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 28 18:58:47 PDT 2022
Author: Johannes Doerfert
Date: 2022-03-28T20:57:52-05:00
New Revision: bb0b23174e4ab963df427393fbf21bddede499bf
URL: https://github.com/llvm/llvm-project/commit/bb0b23174e4ab963df427393fbf21bddede499bf
DIFF: https://github.com/llvm/llvm-project/commit/bb0b23174e4ab963df427393fbf21bddede499bf.diff
LOG: [InstCombineCalls] Optimize call of bitcast even w/ parameter attributes
Before we gave up if a call through bitcast had parameter attributes.
Interestingly, we allowed attributes for the return value already. We
now handle both the same way, namely, we drop the ones that are
incompatible with the new type and keep the rest. This cannot cause
"more UB" than initially present.
Differential Revision: https://reviews.llvm.org/D119967
Added:
Modified:
llvm/include/llvm/IR/Attributes.h
llvm/lib/IR/Attributes.cpp
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
llvm/test/Transforms/InstCombine/call-cast-attrs.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 61819b1a07fad..cc2b16be073ae 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -1211,8 +1211,17 @@ class AttrBuilder {
namespace AttributeFuncs {
-/// Which attributes cannot be applied to a type.
-AttributeMask typeIncompatible(Type *Ty);
+enum AttributeSafetyKind : uint8_t {
+ ASK_SAFE_TO_DROP = 1,
+ ASK_UNSAFE_TO_DROP = 2,
+ ASK_ALL = ASK_SAFE_TO_DROP | ASK_UNSAFE_TO_DROP,
+};
+
+/// Which attributes cannot be applied to a type. The argument \p ASK indicates,
+/// if only attributes that are known to be safely droppable are contained in
+/// the mask; only attributes that might be unsafe to drop (e.g., ABI-related
+/// attributes) are in the mask; or both.
+AttributeMask typeIncompatible(Type *Ty, AttributeSafetyKind ASK = ASK_ALL);
/// Get param/return attributes which imply immediate undefined behavior if an
/// invalid value is passed. For example, this includes noundef (where undef
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 767767cdae0c3..c4759f858a2e7 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -1773,40 +1773,50 @@ bool AttrBuilder::operator==(const AttrBuilder &B) const {
//===----------------------------------------------------------------------===//
/// Which attributes cannot be applied to a type.
-AttributeMask AttributeFuncs::typeIncompatible(Type *Ty) {
+AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
+ AttributeSafetyKind ASK) {
AttributeMask Incompatible;
- if (!Ty->isIntegerTy())
+ if (!Ty->isIntegerTy()) {
// Attributes that only apply to integers.
- Incompatible.addAttribute(Attribute::SExt)
- .addAttribute(Attribute::ZExt)
- .addAttribute(Attribute::AllocAlign);
+ if (ASK & ASK_SAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::AllocAlign);
+ if (ASK & ASK_UNSAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);
+ }
- if (!Ty->isPointerTy())
+ if (!Ty->isPointerTy()) {
// Attributes that only apply to pointers.
- Incompatible.addAttribute(Attribute::Nest)
- .addAttribute(Attribute::NoAlias)
- .addAttribute(Attribute::NoCapture)
- .addAttribute(Attribute::NonNull)
- .addAttribute(Attribute::ReadNone)
- .addAttribute(Attribute::ReadOnly)
- .addAttribute(Attribute::SwiftError)
- .addAttribute(Attribute::Dereferenceable)
- .addAttribute(Attribute::DereferenceableOrNull)
- .addAttribute(Attribute::Preallocated)
- .addAttribute(Attribute::InAlloca)
- .addAttribute(Attribute::ByVal)
- .addAttribute(Attribute::StructRet)
- .addAttribute(Attribute::ByRef)
- .addAttribute(Attribute::ElementType);
-
- if (!Ty->isPtrOrPtrVectorTy())
+ if (ASK & ASK_SAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::NoAlias)
+ .addAttribute(Attribute::NoCapture)
+ .addAttribute(Attribute::NonNull)
+ .addAttribute(Attribute::ReadNone)
+ .addAttribute(Attribute::ReadOnly)
+ .addAttribute(Attribute::Dereferenceable)
+ .addAttribute(Attribute::DereferenceableOrNull);
+ if (ASK & ASK_UNSAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::Nest)
+ .addAttribute(Attribute::SwiftError)
+ .addAttribute(Attribute::Preallocated)
+ .addAttribute(Attribute::InAlloca)
+ .addAttribute(Attribute::ByVal)
+ .addAttribute(Attribute::StructRet)
+ .addAttribute(Attribute::ByRef)
+ .addAttribute(Attribute::ElementType);
+ }
+
// Attributes that only apply to pointers or vectors of pointers.
- Incompatible.addAttribute(Attribute::Alignment);
+ if (!Ty->isPtrOrPtrVectorTy()) {
+ if (ASK & ASK_SAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::Alignment);
+ }
// Some attributes can apply to all "values" but there are no `void` values.
- if (Ty->isVoidTy())
- Incompatible.addAttribute(Attribute::NoUndef);
+ if (Ty->isVoidTy()) {
+ if (ASK & ASK_SAFE_TO_DROP)
+ Incompatible.addAttribute(Attribute::NoUndef);
+ }
return Incompatible;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index d66efa49c15e9..ed5b8d0397f9a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3198,12 +3198,15 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
if (!CastInst::isBitOrNoopPointerCastable(ActTy, ParamTy, DL))
return false; // Cannot transform this parameter value.
+ // Check if there are any incompatible attributes we cannot drop safely.
if (AttrBuilder(FT->getContext(), CallerPAL.getParamAttrs(i))
- .overlaps(AttributeFuncs::typeIncompatible(ParamTy)))
+ .overlaps(AttributeFuncs::typeIncompatible(
+ ParamTy, AttributeFuncs::ASK_UNSAFE_TO_DROP)))
return false; // Attribute not compatible with transformed value.
- if (Call.isInAllocaArgument(i))
- return false; // Cannot transform to and from inalloca.
+ if (Call.isInAllocaArgument(i) ||
+ CallerPAL.hasParamAttr(i, Attribute::Preallocated))
+ return false; // Cannot transform to and from inalloca/preallocated.
if (CallerPAL.hasParamAttr(i, Attribute::SwiftError))
return false;
@@ -3281,14 +3284,20 @@ bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
NewArg = Builder.CreateBitOrPointerCast(*AI, ParamTy);
Args.push_back(NewArg);
- // Add any parameter attributes.
+ // Add any parameter attributes except the ones incompatible with the new
+ // type. Note that we made sure all incompatible ones are safe to drop.
+ AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(
+ ParamTy, AttributeFuncs::ASK_SAFE_TO_DROP);
if (CallerPAL.hasParamAttr(i, Attribute::ByVal) &&
!ParamTy->isOpaquePointerTy()) {
- AttrBuilder AB(FT->getContext(), CallerPAL.getParamAttrs(i));
- AB.addByValAttr(ParamTy->getNonOpaquePointerElementType());
+ AttrBuilder AB(Ctx, CallerPAL.getParamAttrs(i).removeAttributes(
+ Ctx, IncompatibleAttrs));
+ AB.addByValAttr(NewArg->getType()->getPointerElementType());
ArgAttrs.push_back(AttributeSet::get(Ctx, AB));
- } else
- ArgAttrs.push_back(CallerPAL.getParamAttrs(i));
+ } else {
+ ArgAttrs.push_back(
+ CallerPAL.getParamAttrs(i).removeAttributes(Ctx, IncompatibleAttrs));
+ }
}
// If the function takes more arguments than the call was taking, add them
diff --git a/llvm/test/Transforms/InstCombine/call-cast-attrs.ll b/llvm/test/Transforms/InstCombine/call-cast-attrs.ll
index 172a3361e9d54..4fedd81981f39 100644
--- a/llvm/test/Transforms/InstCombine/call-cast-attrs.ll
+++ b/llvm/test/Transforms/InstCombine/call-cast-attrs.ll
@@ -1,4 +1,5 @@
-; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -passes=instcombine -data-layout="p:32:32" -S | FileCheck %s --check-prefixes=CHECK,CHECK32
+; RUN: opt < %s -passes=instcombine -data-layout="p:64:64" -S | FileCheck %s --check-prefixes=CHECK,CHECK64
define signext i32 @b(i32* inreg %x) {
ret i32 0
@@ -20,10 +21,16 @@ define void @g(i32* %y) {
call void bitcast (void (...)* @c to void (i32*)*)(i32* %y)
call void bitcast (void (...)* @c to void (i32*)*)(i32* sret(i32) %y)
call void bitcast (void (i32, ...)* @d to void (i32, i32*)*)(i32 0, i32* sret(i32) %y)
+ call void bitcast (void (i32, ...)* @d to void (i32, i32*)*)(i32 0, i32* nocapture %y)
+ call void bitcast (void (i32, ...)* @d to void (i32*)*)(i32* nocapture noundef %y)
ret void
}
; CHECK-LABEL: define void @g(i32* %y)
-; CHECK: call i32 bitcast (i32 (i32*)* @b to i32 (i32)*)(i32 zeroext 0)
-; CHECK: call void (...) @c(i32* %y)
-; CHECK: call void bitcast (void (...)* @c to void (i32*)*)(i32* sret(i32) %y)
-; CHECK: call void bitcast (void (i32, ...)* @d to void (i32, i32*)*)(i32 0, i32* sret(i32) %y)
+; CHECK: call i32 bitcast (i32 (i32*)* @b to i32 (i32)*)(i32 zeroext 0)
+; CHECK: call void (...) @c(i32* %y)
+; CHECK: call void bitcast (void (...)* @c to void (i32*)*)(i32* sret(i32) %y)
+; CHECK: call void bitcast (void (i32, ...)* @d to void (i32, i32*)*)(i32 0, i32* sret(i32) %y)
+; CHECK: call void (i32, ...) @d(i32 0, i32* nocapture %y)
+; CHECK32: %2 = ptrtoint i32* %y to i32
+; CHECK32: call void (i32, ...) @d(i32 noundef %2)
+; CHECK64: call void bitcast (void (i32, ...)* @d to void (i32*)*)(i32* nocapture noundef %y)
More information about the llvm-commits
mailing list