This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
---|---|---|
516 | Could you elaborate on when would this happen? I'd expect the traversal to always visit the predecessor basic blocks first and within a basic block always visit subexpressions first. So I'd be quite surprised if there is a subexpression we did not visit. |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
---|---|---|
516 | From what I've seen, logic operators influence the structure of the CFG through additional basic blocks and terminators, but their sub-expression operators are not added directly in the basic blocks. For example: void test(bool a, bool b, bool c) { bool d = a && (b || c); } results in: void test(bool a, bool b, bool c) [B5 (ENTRY)] Succs (1): B4 [B1] 1: [B4.2] && ([B3.2] || [B2.2]) 2: bool d = a && (b || c); Preds (3): B2 B3 B4 Succs (1): B0 [B2] 1: c 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool) Preds (1): B3 Succs (1): B1 [B3] 1: b 2: [B3.1] (ImplicitCastExpr, LValueToRValue, _Bool) T: [B3.2] || ... Preds (1): B4 Succs (2): B1 B2 [B4] 1: a 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) T: [B4.2] && ... Preds (1): B5 Succs (2): B3 B1 [B0 (EXIT)] Preds (1): B1 So, when we evaluate a && (b || c) in B1, the sub-expression b || c has not been evaluated yet. I updated the comment in the code to make that more clear. |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
---|---|---|
516 | I understand the structure of the CFG and also understand that certain subexpressions are in different basic blocks. But I still don't understand why would b || c be not evaluated when we evaluate a && (b || c). The operator && in your example is evaluated in B1. The operator || is evaluated in B3. B3 is a predecessor of B1, so if we process the CFG in reverse-post order, we should visit B3 before B1. I am pretty sure if the traversal is well-written we should have the || evaluated before we visit B1. I suspect that something different might be going on. Is it possible that you want to evaluate the && in B4? Note that && is a terminator there because of the short-circuiting. So at that point we should NOT ask for the value of ||. |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
---|---|---|
516 |
I don't think that's the case. Similar to your observation about && being a terminator in B4, I believe that || is a terminator in B3. I interpret B3 as the "a is true" branch. It still doesn't contain information about b and c which might be subject to short-circuiting. Does that make sense? |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
---|---|---|
516 | Oh, I see now! Sorry, I somehow assumed Visit is recursive. But you only visit the top level operator not the whole subexpression. Yeah, I understand now, thanks! This looks good to me. |
Could you elaborate on when would this happen? I'd expect the traversal to always visit the predecessor basic blocks first and within a basic block always visit subexpressions first. So I'd be quite surprised if there is a subexpression we did not visit.