This is an archive of the discontinued LLVM Phabricator instance.

Make Argument::getArgNo() constant time, not O(#args)
ClosedPublic

Authored by rnk on Mar 16 2017, 2:56 PM.

Details

Summary

getArgNo is actually hot in LLVM, because its how we check for
attributes on arguments:

bool Argument::hasNonNullAttr() const {
  if (!getType()->isPointerTy()) return false;
  if (getParent()->getAttributes().
        hasAttribute(getArgNo()+1, Attribute::NonNull))
    return true;

It actually shows up as the 23rd hottest leaf function in a 13s sample
of LTO of llc.

This grows Argument by four bytes, but I have another pending patch to
shrink it by removing its ilist_node base.

Diff Detail

Repository
rL LLVM

Event Timeline

rnk created this revision.Mar 16 2017, 2:56 PM
chandlerc accepted this revision.Mar 16 2017, 3:24 PM

This seems like a very reasonable tradeoff and a clean patch. Especially reasonable given the subsequent improvements. Ship it.

This revision is now accepted and ready to land.Mar 16 2017, 3:24 PM
This revision was automatically updated to reflect the committed changes.

It actually shows up as the 23rd hottest leaf function in a 13s sample of LTO of llc.

Impressive! Nice finding :)

Hi,
This seems like a nice optimization.

I was just wondering if it is a good idea to silently push this with a default argument for ArgNo. there is other locations in LLVM where an Argument object is constructed with the default parameter without realizing that this will break their getArgNo.

for example:
git grep -n "new Argument("
lib/AsmParser/LLParser.cpp:2533: FwdVal = new Argument(Ty, Name);
lib/AsmParser/LLParser.cpp:2573: FwdVal = new Argument(Ty);
lib/Bitcode/Reader/ValueList.cpp:116: Value *V = new Argument(Ty);

rnk added a comment.Mar 29 2017, 10:49 AM

Hi,
This seems like a nice optimization.

Thanks!

I was just wondering if it is a good idea to silently push this with a default argument for ArgNo. there is other locations in LLVM where an Argument object is constructed with the default parameter without realizing that this will break their getArgNo.

for example:
git grep -n "new Argument("
lib/AsmParser/LLParser.cpp:2533: FwdVal = new Argument(Ty, Name);
lib/AsmParser/LLParser.cpp:2573: FwdVal = new Argument(Ty);
lib/Bitcode/Reader/ValueList.cpp:116: Value *V = new Argument(Ty);

These arguments are all only ever used to forward declare a Value. They never have a parent function. getArgNo() will return 0, but if getParent() returns null, what does that really mean?

After searching for calls to new Argument across clang and LLVM, I realized that everyone uses the code in Function to construct the argument list. Perhaps one nice side effect of eliminating this field and computing getArgNo() from getParent() is that it would be impossible to get the argument number of an unparented argument. That seems like a better argument for doing it than the memory usage of this field.