[cfe-dev] CFG temporary objects destructors

Zhongxing Xu xuzhongxing at gmail.com
Sun Oct 24 22:29:52 PDT 2010


On Mon, Oct 25, 2010 at 1:19 PM, Ted Kremenek <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> wrote:
>
>> On Oct 24, 2010, at 7:57 PM, Zhongxing Xu <xuzhongxing at gmail.com> wrote:
>>
>>
>>
>> On Mon, Oct 25, 2010 at 2:13 AM, Ted Kremenek < <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> wrote:
>>>
>>>
>>>
>>> 2010/10/23 Ted Kremenek < <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?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101025/6725e516/attachment.html>


More information about the cfe-dev mailing list