[cfe-commits] r65694 - in /cfe/trunk: include/clang/Parse/Scope.h lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclObjC.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaStmt.cpp test/Sema/block-labels.c

steve naroff snaroff at apple.com
Sat Feb 28 20:26:40 PST 2009


On Feb 28, 2009, at 9:38 PM, Chris Lattner wrote:

> On Feb 28, 2009, at 1:05 PM, steve naroff wrote:
>>> Thanks for working on this Steve.  I somewhat concerned about the  
>>> cost of this though: scopes are very frantically pushed and  
>>> popped, and adding a densemap to them seems potentially  
>>> expensive.  Two possible solutions: 1) use a separate explicit  
>>> stack for these, or 2) make scope contain a pointer to a (lazily  
>>> initialized) densemap instead of containing it by value.  #2 would  
>>> only penalize scopes that actually contain labels which are pretty  
>>> rare.
>>>
>>> What do you think?
>>>
>>
>> I considered #1, however it seemed cleaner to leverage the existing  
>> Scope mechanism (which is a catch-all by design).
>>
>> Is the cost to setup an empty DenseMap much greater than setting up  
>> an empty SmallVector? If so, then I guess I'd prefer #2.
>
> It is not amazingly expensive (the first malloc happens on the first  
> insert) but a densemap is 4 words, so this significantly increases  
> the size of Scope.
>
>> I don't have a strong opinion. Just let me know what you prefer and  
>> I'll take care of it.
>
> I agree with you that #1 is gross.  #2 seems reasonable.
>

O.K., however the next issue is related and raises a 3rd alternative.

>>
>>
>>>>
>>>> +  /// ActiveScope - If inside of a function, method, or block  
>>>> definition,
>>>> +  /// this contains a pointer to the active scope that  
>>>> represents it.
>>>> +  Scope *ActiveScope;
>>>
>>>> +  /// PrevFunctionScope - This is the scope for the enclosing  
>>>> function.
>>>> +  /// For global blocks, this will be null.
>>>> +  Scope *PrevFunctionScope;
>>>
>>> How are these different?  Have you seen that Scope has a bunch of  
>>> things like FnParent etc that make getting this information very  
>>> cheap.  It seems best to use these pointers because they are  
>>> guaranteed up to date and don't require new code to maintain them.
>>>
>>
>> Just committed a fix for this (good catch).
>
> Ok, you removed PrevFunctionScope (yay!) but kept ActiveScope.  What  
> is ActiveScope? Can it be removed?

ActiveScope allows ActOnLabelStmt/ActOnAddrLabel/ActOnGotoStmt/ 
ActOnFinishFunctionBody to perform their operations (generically) on  
the respective function/method/block.

If we decided to remove it, the ActOn label-related functions above  
*could* use CurBlock to decipher it's context (making the actions a  
bit more complex). If we decided to do this, the LabelMap in Scope  
would need to be in 2 places: One in BlockSemaInfo (for the block  
stack), and one in Sema (for functions, like we had prior to this bug  
fix). From a performance perspective, this makes the most sense (since  
it places the overhead where it belongs).

>
>
>>>> +  // FIXME: Temporary hack to workaround nested C++ functions.  
>>>> For example:
>>>> +  // class C2 {
>>>> +  //   void f() {
>>>> +  //     class LC1 {
>>>> +  //       int m() { return 1; }
>>>> +  //     };
>>>> +  //   }
>>>> +  // };
>>>> +  if (ActiveScope == 0)
>>>> +    return D;
>>>> +
>>>
>>> I don't understand the issue here.  Why doesn't this work?
>>
>> The code was crashing because ActiveScope was null.
>
> Ok, but why?

Because the ActOnStartOfFunctionDef/ActOnFinishFunctionBody don't  
implement a stack (since C/ObjC functions never nest). Not difficult  
to fix.

We could consider morphing BlockSemaInfo into NestedFunctionInfo  
(where blocks would be a client).

>
>
>>>> // If not forward referenced or defined already, just create a  
>>>> new LabelStmt.
>>>> +  if (I == ActiveScope->LabelMap.end()) {
>>>> +    LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt);
>>>> +    ActiveScope->LabelMap.insert(std::make_pair(II, LabelDecl));
>>>> +    return Owned(LabelDecl);
>>>> +  } else
>>>> +    LabelDecl = static_cast<LabelStmt *>(I->second);
>>>
>>> Instead of using find+insert, please use the old idiom of  
>>> constructing a reference into the map, something like:
>>>
>>> LabelStmt *&LabelDecl = ActiveScope->LabelMap[II];
>>> if (LabelDecl == 0) {
>>> LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt);
>>> ActiveScope->LabelMap.insert(std::make_pair(II, LabelDecl));
>>> return Owned(LabelDecl);
>>> }
>>>
>>> This eliminates a lookup for the insert.
>>
>> I tried doing this, however C++ casting seemed to get in my way. Is  
>> it possible to do what you want when the LabelMap is declared to  
>> take a "void *"?
>
> Yes, use:
>
> Action::StmtTy *&LabelDecl = ActiveScope->LabelMap[II];
>

O.k. I'll see if that simplifies the code...

snaroff

> Thanks Steve,
>
> -Chris
>




More information about the cfe-commits mailing list