[cfe-dev] CFG temporary objects destructors

Marcin Świderski marcin.sfider at gmail.com
Thu Oct 28 13:39:43 PDT 2010


2010/10/25 Zhongxing Xu <xuzhongxing at gmail.com>

> On Mon, Oct 25, 2010 at 1:55 PM, Ted Kremenek <kremenek at apple.com> wrote:
>
>> On Oct 24, 2010, at 10:29 PM, Zhongxing Xu <xuzhongxing at gmail.com> wrote:
>>
>> On Mon, Oct 25, 2010 at 1:19 PM, Ted Kremenek < <kremenek at apple.com>
>> kremenek at apple.com> wrote:
>>
>>> On Oct 24, 2010, at 9:52 PM, Zhongxing Xu wrote:
>>>
>>> On Mon, Oct 25, 2010 at 12:24 PM, Ted Kremenek < <kremenek at apple.com>
>>> kremenek at apple.com> wrote:
>>>
>>>> On Oct 24, 2010, at 7:57 PM, Zhongxing Xu < <xuzhongxing at gmail.com>
>>>> xuzhongxing at gmail.com> wrote:
>>>>
>>>> On Mon, Oct 25, 2010 at 2:13 AM, Ted Kremenek < <kremenek at apple.com><kremenek at apple.com>
>>>> kremenek at apple.com> wrote:
>>>>
>>>>> On Oct 22, 2010, at 10:41 PM, Zhongxing Xu < <xuzhongxing at gmail.com><xuzhongxing at gmail.com>
>>>>> xuzhongxing at gmail.com> wrote:
>>>>>
>>>>> 2010/10/23 Ted Kremenek < <kremenek at apple.com> <kremenek at apple.com><kremenek at apple.com>
>>>>> kremenek at apple.com>
>>>>>
>>>>>> On Oct 17, 2010, at 3:06 PM, Marcin Świderski wrote:
>>>>>>
>>>>>> > Blocks structure that is constructed is fine, but I don't know what
>>>>>> to use for terminator of block initiating the branch and for first element
>>>>>> in block closing the branch (I didn't check this yet, but I think that it
>>>>>> could be used during backward analysis). Could I use fake if/else statement
>>>>>> for this? Similar solution is used to make every declaration into separate
>>>>>> statement.
>>>>>>
>>>>>> What we could do is generalize terminators in the same way we did with
>>>>>> CFGElements.  Right now terminators are Stmt*, but they could be something
>>>>>> like CFGTerminator, which could discriminate between regular terminators and
>>>>>> those used for blocks guarding destructor calls.  The CFGTerminator for
>>>>>> those blocks could essentially be the same Stmt* as the terminator guarding
>>>>>> the block with the constructor, but with a special bit indicating it is for
>>>>>> the matching destructor(s).  The nice thing about this approach is that it
>>>>>> naturally ties the two blocks together, they can share the same condition
>>>>>> values, etc.
>>>>>
>>>>>
>>>>> We need a way to convey the branch information to the second logical op
>>>>> used as terminator. At first we bind logical op to a UndefinedVal which
>>>>> indicates which branch is taken. Then the logical op is bound to its real
>>>>> value. At the second terminator where the logical op appears, we still need
>>>>> the taken branch information to decide which branch to take.
>>>>>
>>>>>
>>>>> Indeed.  After thinking about this some more, we can't just keep a
>>>>> reference the original block-level expression that represented the branch
>>>>> condition and hope that is enough.  That expression's SVal should still be
>>>>> in the Environment (since it would still be live), and we could use it a
>>>>> second time when deciding the branch.  That only works, however, if we only
>>>>> took a single branch (not both of them) and the SVal didn't reference any
>>>>> symbolic values (which depend on state).  Thus recording the branch taken
>>>>> seems to be the most accurate and simplest approach.
>>>>>
>>>>> We could possibly insert this information into the Environment
>>>>> (possibly using some bit mangling for the Stmt* key value), have the data
>>>>> value represent the branch taken, and then have the liveness of that entry
>>>>> be the same as the liveness of the original condition expression.
>>>>>
>>>>> For example, in A || B, the expression 'A' is used to determine the
>>>>> first branch.  For that, we have a block-level expression (a Stmt*) which
>>>>> serves as a condition for the terminator '||'.  That value gets inserted
>>>>> into the Environment as part of regular evaluation, and stays live until
>>>>> after we are done with evaluating the '||' terminator (LiveVariables
>>>>> analysis does this for us).  In addition, we could insert another entry
>>>>> whose key is similar to the one for the block-level expression but instead
>>>>> has a bit twiddled (e.g., we take the Stmt* for 'A', which represents the
>>>>> condition value used for the first branch, and then bit-mangle it).  We
>>>>> could use that to record what branch we took, and keep that entry around as
>>>>> long as the original block-level expression (e.g., the Stmt* for 'A') would
>>>>> stay in the Environment.  That value's lifetime would get extended by having
>>>>> a special CFGTerminator that referenced that block-level expression and
>>>>> represented the terminator for jumping to the block with the destructor
>>>>> calls.  We then consult the branch value when choosing what block to jump to
>>>>> for the destructors.
>>>>>
>>>>
>>>> That means we need to modify the dataflow solver since the Terminator
>>>> does not participate the dataflow computation for now, right?
>>>>
>>>>
>>> Sorry, I didn't get this clear. I am concerning the liveness computation.
>>> We need to keep the bit-mangled Stmt* for 'A' alive until the second logical
>>> op as terminator. Since it is only referenced by this terminator, we need to
>>> modify the dataflow solver to consider terminators when doing the
>>> computation.
>>>
>>>
>>> Ah, I see.  DataflowSolver already calls 'VisitTerminator', and
>>> LiveVariables.cpp already checks the terminator as part of the liveness
>>> computation.  I don't think we'd really need to do much more other than
>>> educate LiveVariables.cpp about the new terminators.  The DataflowSolver
>>> itself wouldn't need to be changed.
>>>
>>
>> I see. And we also need to insert the bit-mangled Stmt * into the
>> CFGBlock, otherwise it won't appear in the LiveVariables. So we need to
>> create a new kind of CFGElement, say, BranchMarker?
>>
>>
>> I don't immediately see a need to do that.  Since LiveVariables is a
>> reverse dataflow analysis, the bit-mangled Stmt* can get inserted (as
>> "live") when we visit the terminator.  It can then get removed when we visit
>> the original Stmt* (which by definition dominates the point where we'd
>> consult the bit-mangled Stmt*).  I don't see a need to add a special
>> BranchMarker.  Is there a case that I'm missing?
>>
>
> Makes sense. To clarify, the bit-mangled Stmt* should be the logical op 'A
> || B', since it is the one that is reference by the terminator.
>

Could you please review my patch on CFGTerminator class? As I understand it
should allow for appropriate changes in LiveVariables, and will allow me to
finish implementation of destructors of termporaries in CFG. Thanks in
advance.

- Marcin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101028/221729ba/attachment.html>


More information about the cfe-dev mailing list