aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/InlineFunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Utils/InlineFunction.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp90
1 files changed, 74 insertions, 16 deletions
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index 55ad2b6d..71ca527 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -34,6 +34,7 @@
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/AttributeMask.h"
+#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constant.h"
@@ -59,6 +60,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/ProfDataUtils.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
@@ -1358,18 +1360,36 @@ static void AddParamAndFnBasicAttributes(const CallBase &CB,
auto &Context = CalledFunction->getContext();
// Collect valid attributes for all params.
- SmallVector<AttrBuilder> ValidParamAttrs;
+ SmallVector<AttrBuilder> ValidObjParamAttrs, ValidExactParamAttrs;
bool HasAttrToPropagate = false;
+ // Attributes we can only propagate if the exact parameter is forwarded.
+ // We can propagate both poison generating and UB generating attributes
+ // without any extra checks. The only attribute that is tricky to propagate
+ // is `noundef` (skipped for now) as that can create new UB where previous
+ // behavior was just using a poison value.
+ static const Attribute::AttrKind ExactAttrsToPropagate[] = {
+ Attribute::Dereferenceable, Attribute::DereferenceableOrNull,
+ Attribute::NonNull, Attribute::Alignment, Attribute::Range};
+
for (unsigned I = 0, E = CB.arg_size(); I < E; ++I) {
- ValidParamAttrs.emplace_back(AttrBuilder{CB.getContext()});
+ ValidObjParamAttrs.emplace_back(AttrBuilder{CB.getContext()});
+ ValidExactParamAttrs.emplace_back(AttrBuilder{CB.getContext()});
// Access attributes can be propagated to any param with the same underlying
// object as the argument.
if (CB.paramHasAttr(I, Attribute::ReadNone))
- ValidParamAttrs.back().addAttribute(Attribute::ReadNone);
+ ValidObjParamAttrs.back().addAttribute(Attribute::ReadNone);
if (CB.paramHasAttr(I, Attribute::ReadOnly))
- ValidParamAttrs.back().addAttribute(Attribute::ReadOnly);
- HasAttrToPropagate |= ValidParamAttrs.back().hasAttributes();
+ ValidObjParamAttrs.back().addAttribute(Attribute::ReadOnly);
+
+ for (Attribute::AttrKind AK : ExactAttrsToPropagate) {
+ Attribute Attr = CB.getParamAttr(I, AK);
+ if (Attr.isValid())
+ ValidExactParamAttrs.back().addAttribute(Attr);
+ }
+
+ HasAttrToPropagate |= ValidObjParamAttrs.back().hasAttributes();
+ HasAttrToPropagate |= ValidExactParamAttrs.back().hasAttributes();
}
// Won't be able to propagate anything.
@@ -1391,22 +1411,60 @@ static void AddParamAndFnBasicAttributes(const CallBase &CB,
AttributeList AL = NewInnerCB->getAttributes();
for (unsigned I = 0, E = InnerCB->arg_size(); I < E; ++I) {
- // Check if the underlying value for the parameter is an argument.
- const Value *UnderlyingV =
- getUnderlyingObject(InnerCB->getArgOperand(I));
- const Argument *Arg = dyn_cast<Argument>(UnderlyingV);
- if (!Arg)
+ // It's unsound or requires special handling to propagate
+ // attributes to byval arguments. Even if CalledFunction
+ // doesn't e.g. write to the argument (readonly), the call to
+ // NewInnerCB may write to its by-value copy.
+ if (NewInnerCB->paramHasAttr(I, Attribute::ByVal))
continue;
- if (NewInnerCB->paramHasAttr(I, Attribute::ByVal))
- // It's unsound to propagate memory attributes to byval arguments.
- // Even if CalledFunction doesn't e.g. write to the argument,
- // the call to NewInnerCB may write to its by-value copy.
+ // Don't bother propagating attrs to constants.
+ if (match(NewInnerCB->getArgOperand(I),
+ llvm::PatternMatch::m_ImmConstant()))
continue;
- unsigned ArgNo = Arg->getArgNo();
+ // Check if the underlying value for the parameter is an argument.
+ const Argument *Arg = dyn_cast<Argument>(InnerCB->getArgOperand(I));
+ unsigned ArgNo;
+ if (Arg) {
+ ArgNo = Arg->getArgNo();
+ // For dereferenceable, dereferenceable_or_null, align, etc...
+ // we don't want to propagate if the existing param has the same
+ // attribute with "better" constraints. So remove from the
+ // new AL if the region of the existing param is larger than
+ // what we can propagate.
+ AttrBuilder NewAB{
+ Context, AttributeSet::get(Context, ValidExactParamAttrs[ArgNo])};
+ if (AL.getParamDereferenceableBytes(I) >
+ NewAB.getDereferenceableBytes())
+ NewAB.removeAttribute(Attribute::Dereferenceable);
+ if (AL.getParamDereferenceableOrNullBytes(I) >
+ NewAB.getDereferenceableOrNullBytes())
+ NewAB.removeAttribute(Attribute::DereferenceableOrNull);
+ if (AL.getParamAlignment(I).valueOrOne() >
+ NewAB.getAlignment().valueOrOne())
+ NewAB.removeAttribute(Attribute::Alignment);
+ if (auto ExistingRange = AL.getParamRange(I)) {
+ if (auto NewRange = NewAB.getRange()) {
+ ConstantRange CombinedRange =
+ ExistingRange->intersectWith(*NewRange);
+ NewAB.removeAttribute(Attribute::Range);
+ NewAB.addRangeAttr(CombinedRange);
+ }
+ }
+ AL = AL.addParamAttributes(Context, I, NewAB);
+ } else {
+ // Check if the underlying value for the parameter is an argument.
+ const Value *UnderlyingV =
+ getUnderlyingObject(InnerCB->getArgOperand(I));
+ Arg = dyn_cast<Argument>(UnderlyingV);
+ if (!Arg)
+ continue;
+ ArgNo = Arg->getArgNo();
+ }
+
// If so, propagate its access attributes.
- AL = AL.addParamAttributes(Context, I, ValidParamAttrs[ArgNo]);
+ AL = AL.addParamAttributes(Context, I, ValidObjParamAttrs[ArgNo]);
// We can have conflicting attributes from the inner callsite and
// to-be-inlined callsite. In that case, choose the most
// restrictive.