Skip to content
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

LLVM should have a nocapture parameter attribute for functions that don't let a pointer value escape #2427

Closed
llvmbot opened this issue Feb 18, 2008 · 10 comments
Assignees
Labels
bugzilla Issues migrated from bugzilla

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented Feb 18, 2008

Bugzilla Link 2055
Resolution FIXED
Resolved on Feb 08, 2009 16:42
Version unspecified
OS All
Reporter LLVM Bugzilla Contributor
CC @nlewycky

Extended Description

Chris pointed out that it would be useful to have a "nocapture" parameter attribute. Its semantics would be that a pointer value passed in with the "nocapture" attribute can be assumed never to escape from the callee (never stored to a global or passed to another function where it could escape).

@llvmbot
Copy link
Collaborator Author

llvmbot commented Feb 18, 2008

assigned to @nlewycky

@lattner
Copy link
Collaborator

lattner commented Feb 18, 2008

This could make AddressMightEscape more aggressive in BasicAA, giving better mod/ref info for calls. This property is true of a huge variety of pointer arguments to functions, e.g. strlen, memcpy, etc. Knowledge of this property allows us to optimize things like this:

char buffer[100];
buffer[0] = 0;

strlen(buffer); // buffer doesn't escape

x = buffer[0];
foo(); // can't modify buffer because strlen doesn't cause it to escape
y = buffer[0]; // always = x

This property could also be inferred for a lot of functions by globalsmodref.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Feb 18, 2008

Since strlen is 'readonly' this doesn't seem like a good example.

@lattner
Copy link
Collaborator

lattner commented Feb 18, 2008

The point here is that strlen doesn't capture the pointer, so foo couldn't modify it. nocapture and readonly are orthogonal concepts.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Feb 18, 2008

Can a readonly function capture a pointer? It can't write it
into a global variable because it is readonly. I guess it could
encode the pointer in the value it returns...

@lattner
Copy link
Collaborator

lattner commented Feb 18, 2008

This is readnone but does capture its argument:
int *foo(int *X) { return X; }

@llvmbot
Copy link
Collaborator Author

llvmbot commented Feb 19, 2008

OK, but llvm-gcc nonetheless seems to have no trouble
simplifying your example! I presume the plan is to
enhance the gcc tables (which list properties like 'const'
for a bunch of functions) so they also have 'nocapture' info.

Also, what is the policy with attribute propagation vs having
an analysis? We get some attributes from the front-end, which
set them using special front-end knowledge. I'm thinking of
'readnone' and 'readonly'. There is an analysis pass GlobalsModRef
which can (presumably) deduce readnone/readonly for some functions
for which we have the body. A transform could be built on top of
GlobalsModRef that sets readnone/readonly on those functions. But
what's the point of propagating attributes in this way if we have
the analysis anyway?

My answer is that it speeds things up if later the module is
linked with another one and reoptimized.

I like the structure of having (1) an attribute deducing analysis
and (2) an attribute setting transform. Currently for 'nounwind'
these two are lumped into one (PruneEH). Logically it should probably
be split, and places that want to know if a function can unwind should
query the analysis. Right now this is probably not worth it, but once
trapping instructions are implemented that might change.

@lattner
Copy link
Collaborator

lattner commented Feb 19, 2008

OK, but llvm-gcc nonetheless seems to have no trouble
simplifying your example!

It must be 'proving' that it is unnecessary some other way. It would be interesting to find out how it decides it is useless.

I presume the plan is to enhance the gcc tables (which list properties like 'const'
for a bunch of functions) so they also have 'nocapture' info.

That would make sense, alternatively we could add it to simplifylibcalls (yuck), or add a llvm-specific table somewhere in the front-end (less yuck, but still strange). I have no preference for how it is implemented in llvm-gcc.

Also, what is the policy with attribute propagation vs having
an analysis? We get some attributes from the front-end, which
set them using special front-end knowledge. I'm thinking of
'readnone' and 'readonly'.

Right.

There is an analysis pass GlobalsModRef
which can (presumably) deduce readnone/readonly for some functions
for which we have the body. A transform could be built on top of
GlobalsModRef that sets readnone/readonly on those functions. But
what's the point of propagating attributes in this way if we have
the analysis anyway?

I'm not sure what you mean by "we have the analysis anyway". An analysis and attrs are two very different things. Attributes are nice because they can be cheaply computed by a variety of means (e.g. tables) and are efficient to propagate in this case. Analyses are nice because they can do arbitrary weird things, like deciding that the function writes, but only reads one argument, or something. You can also put ad-hoc knowledge into passes, such as the mod/ref behavior of printf or scanf, which requires analyzing the format string.

The current GlobalsModRef was written before we had attributes, so it is probably doing too much or doing what it does in the wrong way now. It should be revisited. Ideally running it wouldn't build up heavy heap datastructures, it would just add propagate and update tags on the functions.

I like the structure of having (1) an attribute deducing analysis
and (2) an attribute setting transform.

Me too :)

Currently for 'nounwind'
these two are lumped into one (PruneEH). Logically it should probably
be split, and places that want to know if a function can unwind should
query the analysis. Right now this is probably not worth it, but once
trapping instructions are implemented that might change.

That would be reasonable too. At this point, I'm mostly concerned with optimizing various memory things, like your crazy memcpy cases, so I'm focused on readonly/nocapture etc, but optimizing and improving EH info is also useful.

-Chris

@lattner
Copy link
Collaborator

lattner commented Dec 8, 2008

The other useful thing about this is that it lets us do partial mem2reg/sroa for stuff that would otherwise be prevented due to byref args. For example:

void foo(int &X) NOINLINE { X = 1; }

int bar() {
int X;
foo(X);

for (i = 0 .. 100)
X += i;
return X;
}

Right now, foo pins X to the stack so mem2reg can't promote it in the loop. If we had no capture, we could promote allocas and just store/reload around calls like this.

-Chris

@nlewycky
Copy link
Contributor

nlewycky commented Feb 9, 2009

I added this a while ago. Missed optz'ns with nocapture should get their own bugs.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 3, 2021
cyndyishida pushed a commit to cyndyishida/llvm-project that referenced this issue Jun 17, 2022
Fix the guaranteed alignment of memory returned by malloc/new on Darwin
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

3 participants