[cfe-dev] Intrinsic/Custom Function Creation with Pragmas

Prakash Prabhu prakash.prabhu at gmail.com
Wed Jan 13 16:36:31 CST 2010


Hi Doug,

One last question (hopefully this is the last bit of change to the frontend
before I move on to the LLVM backend :)). The problem is to specify abstract
Lock conditions using #pragmas as below and have them be translated in C
functions that return an int:

An abstract lock condition could be specified as follows:

#pragma AbstractLockCondn(AbstractLockName(param1, param2, ...), (<C
expression involving params>))

As an example, this is a way by which one could say that a abstract lock L1
is conditioned on variables x and y, where x and y are variables:

#pragma AbstractLockCondn(L1(x,y), (x>y))

What I would like to do is to create a function like the following:

int __L1_Test__(<type of x> x, <type of y> y)
{
  return (x>y);
}

Basically, I can write a #pragma handler in ParsePragma.cpp which will parse
the parameters 1 to n. Much as I would like to invoke the Clang Parser for
parsing the C expression and returning a AST node (root of expression tree)
for the expression, I am doubtful if that is possible:

I will not know the type of the parameters until I see their use sites, at
which point I will look up the types of the variables in the declaration
context having the use sites. So I can't expand the macro at the point where
it is parsed. What I can do at this point, is to push this information into
Sema object.

However, I would know the types at the end of the translation unit at which
point I could potentially generate a function declaration in string and if
possible, insert it into the Preprocessor/TokenLexer stream and then invoke
the parser for parsing this newly generated function. Is this insertion into
the preprocessor/TokenLexer stream possible ? Specifically just before the
call to Actions.ActOnEndOfTranslationUnit() in
Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result), if I can insert the
generated function & its body into the TokenLexer and have the parser
process it by calling ParseExternalDeclaration(). So my question is: Is it
possible to insert the string containing the function body into
token/preprocessor stream and have the parser automatically handle it as if
it were a function defined by the programmer ?

Thanks for your time!

- Prakash

On Sun, Jan 10, 2010 at 1:54 AM, Douglas Gregor <dgregor at apple.com> wrote:

>
> On Jan 9, 2010, at 10:04 PM, Prakash Prabhu <prakash.prabhu at gmail.com>
> wrote:
>
> Hi Doug,
>
> Never mind about the earlier mail. I looked up Lookup.h (!) and was able to
> code in identifier resolution without much hassle and also the creation of
> CallExpr's with appropriate calls to the variadic functions. clang really is
> easy-to-use/modify ... thanks!
>
>
> Glad to hear it!
>
>   - Doug
>
>
>
> On Fri, Jan 8, 2010 at 10:25 PM, Prakash Prabhu <<prakash.prabhu at gmail.com>
> prakash.prabhu at gmail.com> wrote:
>
>> Hi Doug,
>>
>> Thanks a lot for your reply. I was able to add the #pragma, parse it
>> successfully, determine the functions/compound statements to which they are
>> attached by adding code to Sema's ActOnCompoundStmt() and a new function
>> called from ParseFunctionDeclarator(). For the pragmas associated with the
>> function interface, I am able to generate calls in a global function inside
>> the LLVM bit code (by changing CodeGenModule.cpp) to:
>>
>> " void __AbstractLockInfoAtInterface(char* functionName, char*
>> abstractLockName, ...); // the additional parameters are 0/1/2 ...
>> indicating the positional parameters of original function in question. "
>>
>> Multiple pragma's attached to a single block also seem to work (with the
>> help of a pragma stack).
>>
>> Although some of the above places may not be the best (in terms of their
>> actual semantics and diagnostics/error checking which I may need at some
>> point in the future), right now it gets the job done.
>>
>> Now, I am at point where I would like to add calls in the LLVM bit code
>> for compound statements. After looking around in the code for a while,  I
>> still do not have a straightforward solution on how to go about generating
>> calls for compound statments as mentioned in my previous mail:
>>
>> " -- For annotations at client site, insert call for begin/end of the
>> section that is being abstractly locked:
>> void __AbstractLockInfoAtClientSiteBegin(char* abstractLockName, ...); //
>> the additional parameters are Value* representation of the abstract lock
>> parameter variables
>>
>> void __AbstractLockInfoAtClientSiteEnd(char* abstractLockName); // marks
>> the end of the abstract lock scope "
>>
>> The main issue is how to generate the Value* passed in as parameters to
>> __AbstractLockInfoAtClientSiteBegin(), after validating that the variables
>> specified in the #pragma:
>>
>> // L1 is parameterized by x
>> int x;
>> x= ...
>> #pragma AbstractLock L2 x
>> {
>>   int tmp;
>>   tmp = a;
>>   a = tmp + 1;
>> }
>>
>> In the above code, I would like to verify that x is declared and is in
>> scope before I generate a Value* for it in the AbstractLock...Begin function
>> call. I was thinking of the following possibility: In Semantic Actions phase
>> (ActOnCompoundStmt() to be more specific), verify that x is in scope and
>> generate CallExpr before and after the Compound Stmt, wrap this whole triple
>> into a Compound statment and return it. To do this: (a) How do I get access
>> to the variable declaration of 'x' from this point (ActOnCompoundStmt) -- is
>> there a way to walk up the scope tree/AST and at each point look for a
>> declaration of x in some kind of symbol table/declaration structure ? (b) Is
>> there a easy way to create two AST nodes having CallExpr's  to functions
>> that do not have a declaration yet (maybe I need to create the
>> declarations?).
>>
>> Alternatively, if there is way to verify the scope and find the type of
>> the variables used (given just the identifier name), at the code generation
>> time, that would be great too.
>>
>>  Thanks, again, for your time!
>>
>> regards,
>> Prakash
>>
>> On Tue, Jan 5, 2010 at 11:15 AM, Douglas Gregor < <dgregor at apple.com>
>> dgregor at apple.com> wrote:
>>
>>>
>>> On Jan 4, 2010, at 2:37 PM, Prakash Prabhu wrote:
>>>
>>> > Hi,
>>> >
>>> > I would like to define some custom pragmas of the following kind, where
>>> one can associate abstract locks with functions/structured code blocks using
>>> annotations:
>>> >
>>> > Abstract Locks at the function interface level:
>>> > #pragma AbstractLock L1
>>> > void foo();
>>> >
>>> > Abstract Locks for anonymous code blocks:
>>> > #pragma AbstractLock L2
>>> > {
>>> >   int tmp;
>>> >   tmp = a;
>>> >   a = tmp + 1;
>>> > }
>>> >
>>> > Abstract locks could even be parameterized and depend additionally on
>>> variables live at point of specification/function parameters:
>>> >
>>> > // L1 is parameterized by param1 and param2
>>> > #pragma AbstractLock L1 param1 param2
>>> > void foo(int param1, int param2, int param3);
>>>
>>> It might be easier to implement this as a new attribute on functions,
>>> since attributes are automatically associated with declarations or types.
>>> Then, you can avoid the problem of teaching a #pragma that comes *before* a
>>> declaration to associate itself with the correct declaration.
>>>
>>> It might look something like:
>>>
>>>        void __attribute__((lock(L1, param1, param2))) foo(int param1, int
>>> param2, int param3);
>>>
>>> > // L1 is parameterized by x
>>> > int x;
>>> > x= ...
>>> > #pragma AbstractLock L2 x
>>> > {
>>> >   int tmp;
>>> >   tmp = a;
>>> >   a = tmp + 1;
>>> > }
>>> >
>>> > I would like to use clang to pre-process these pragmas, create some
>>> kind of annotation structure in the emitted bit code, for use in the llvm
>>> backend (in one of the opt passes). I was thinking of creating an LLVM
>>> intrinsic/Set of Custom function calls to represent the abstract lock
>>> information in the bit code -- the functions by themselves do not exist and
>>> the only purpose of these calls is to give info to the backend about
>>> abstract locks. I looked at the llvm.annotation intrinsic, but since it uses
>>> a global string, I thought references to variable names (inside the global
>>> string) etc may not remain consistent in wake of front-end
>>> refactoring/optimizations. My current plan is to:
>>> >
>>> > Create a custom Pragma Handler, say, PragmaAbstractLockHandler, that
>>> parses the AbstractLock pragma, and depending on whether the annotation is
>>> at the interface level or inside client code, create calls to the following
>>> functions:
>>> >
>>> > -- For annotations at interface level, insert a call to the following
>>> function into a global section:
>>> > void __AbstractLockInfoAtInterface(char* functionName, char*
>>> abstractLockName, ...); // the additional parameters are 0/1/2 ...
>>> indicating the positional parameters of original function in question.
>>>
>>> > -- For annotations at client site, insert call for begin/end of the
>>> section that is being abstractly locked:
>>> > void __AbstractLockInfoAtClientSiteBegin(char* abstractLockName, ...);
>>> // the additional parameters are Value* representation of the abstract lock
>>> parameter variables
>>> >
>>> > void __AbstractLockInfoAtClientSiteEnd(char* abstractLockName); //
>>> marks the end of the abstract lock scope
>>> >
>>> > The above functions would be immediately processed in the backend as
>>> the first pass of opt (by creating appropriate data structures in the
>>> backend) and calls will be removed from the bit code -- after creating
>>> nonymous functions for the sections of code marked by abstract locks etc..
>>>
>>> This makes perfect sense.
>>>
>>> > I would greatly appreciate any suggestions on how to go about
>>> translating the pragmas to the above functions in clang, or if there might
>>> be a better way to achieve the same with other front-end constructs, that
>>> will be great. How do I create a HandlePragma method that Lexes till the end
>>> of the code section/function declaration, create an Action that adds these
>>> functions in source code ?
>>>
>>>
>>> There's really no way to create a HandlePragma method that lexes until
>>> the end of the code section. Typically, what we do is have HandlePragma set
>>> some state in the Sema object that indicates the presence of your particular
>>> pragma. Then, when Clang parses the corresponding construct (say, a compound
>>> statement), the semantic analysis for that compound statement will check
>>> whether a #pragma was parsed and perform the appropriate transformations.
>>>
>>>        - Doug
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.cs.uiuc.edu/pipermail/cfe-dev/attachments/20100113/3521989b/attachment.html 


More information about the cfe-dev mailing list