-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Inliner] Propagate more attributes to params when inlining #91101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, looking at this code again, shouldn't this be querying the attributes on the CallBase instead of the AttributeList? For example, if you have an existing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. I think this actually implies that we have a bug with out Take: we are propagating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i will post a fix later tonight. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other than the bug with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going to merge this (assuming no objections to the above comment). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, what is your opposition to just cleaning it up explicitly in one place as opposed to having to manage the special cases everywhere? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code is expected to query attributes on CallBase, not the underlying attribute list. If everything works on CallBase, and CallBase implements attribute inheritance correctly, there should not be any special cases relative to the current code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed in query, but not in setting. Seems like a generally easier to design to write whatever is correct to callbase attr list, then let some later pass handle optimizing it properly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I follow. You are already querying the existing attributes here, what difference does it make in terms of complexity to query them on CallBase instead of AttributeList? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, as long we write the |
||
AL = AL.addParamAttributes(Context, I, NewAB); | ||
} else { | ||
// Check if the underlying value for the parameter is an argument. | ||
const Value *UnderlyingV = | ||
dtcxzyw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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. | ||
|
Uh oh!
There was an error while loading. Please reload this page.