[cfe-dev] How to go about generating wrapper functions when a particular attribute is seen?

John McCall via cfe-dev cfe-dev at lists.llvm.org
Sun Nov 26 19:09:56 PST 2017


> On Nov 16, 2017, at 1:02 PM, Seth Goldstein <seth at cmu.edu> wrote:
> 
> The basic goal is the support low-cost parallelism when necessary.
> The wrapper function provides some glue which allows the original
> function to be invoked as a micro-thread.
> 
> So, either the original function or the wrapper function will be
> called, depending on certain conditions.  There are no "ignorant"
> translation units.

Can you elaborate on this?  Is it a dynamic decision or a static decision?  What
happens if we invoke the function as a micro-thread? — because presumably it
executes asynchronously to the caller, but since the function can have a return
value, and that return value can be used, we also presumably need to block on
the micro-thread.  Does that mean that the return value is actually a future?  How
far does the "future-ness" of the return value get propagated before we need to
force it?

My intuition is that, if the goal is for this:

	// do some stuff here
	int result = foo(args);
	// do some more stuff here
	return result;

to not join the micro-thread until the return statement, then you will need to at least
insert the join code in an LLVM pass, because Clang does not do reliable
cross-statement data-flow analysis itself.

Assuming that you don't really care about indirect calls — function pointers, C++
virtual functions, and so on — then it might be easiest overall to do almost all of
the work in an LLVM pass.  Clang would just do the semantic checking on the
attribute and then propagate that down to the LLVM function.  The LLVM function
would correspond to the normal, synchronously-executing version of the function.
Your pass would:

  1. for each function so annotated, create a new micro-thread-spawning function using
      some straightforward name-derivation scheme and

  2. for each direct call to such a function, potentially rewrite the call to use the
      micro-thread-spawning variant.

Unfortunately, doing this on an LLVM level does mean that you might have to
mess around with some ABI ugliness.  For example, if the synchronous function
has a return value that's returned indirectly, and the asynchronous variant just
returns a future, the attributes will need to be adjusted.  Of course, if this is just an
academic proof-of-concept, then you could reasonably just add a semantic condition
that the return type has to be simple in some way — e.g. void, integers, pointers, that
sort of thing — and basically just wish this whole problem away.

> (In fact, as an extra, I would like the attribute
> to be attached to both definitions and declarations so I can check the
> use proper use of these functions.)

That's not the standard C rule, which is that attributes are inherited by redeclarations,
but it's certainly a reasonable enough goal — of course, the usual provisos of
cross-translation-unit semantic enforcement in C apply, but you can do your best.
To do this, you would want to make sure that it was not an InheritableAttr, and you'd
add some logic to Sema::mergeDeclAttributes.

John.

> 
> 
> 
> --------------
> Seth Copen Goldstein
> Carnegie Mellon University
> Computer Science Dept
> 7111 GHC
> 412-268-3828
> 
> On Wed, Nov 15, 2017 at 11:14 PM, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
> 
>> On Nov 15, 2017, at 10:32 PM, Seth Goldstein via cfe-dev <cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>> wrote:
>> 
>> I am wondering what the best approach would be to generate a wrapper
>> function for functions with a particular attribute.  I.e.,
>> 
>> When the compiler sees
>> 
>> __attribute__ ((wrapthis)) int foo(args) {}
>> 
>> I want to generate foo as usual and also generate a function
>> 
>> int
>> foo_wrapper(args)
>> {
>> 	// do some stuff here
>> 	int result = foo(args);
>> 	// do some more stuff here
>> 	return result;
>> }
>> 
>> I am not sure where to generate the wrapper function, e.g., in clang,
>> in llvm?  And, what pass could I look at that might provide me with
>> some hints about how to go about this.  Any help would be appreciated.
> 
> A feature like this could be implemented in many different ways, so it's hard to answer
> your question without more basic information.  How are you anticipating this wrapper
> function being used?  Are all existing uses of the function re-routed to it?  Is it important
> that "ignorant" translation units use the wrapper function?  Is it important that ignorant
> translation units not use the wrapper function?  What's the basic goal here?
> 
> John.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20171126/5276cadf/attachment.html>


More information about the cfe-dev mailing list