Skip to content

Commit d566141

Browse files
authored
Merge pull request #694 from dave-bartolomeo/dave/BetterUnreached
C++: Remove infeasible edges to reachable blocks
2 parents d2d119e + a7cb2d6 commit d566141

File tree

20 files changed

+386
-131
lines changed

20 files changed

+386
-131
lines changed

config/identical-files.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,9 @@
9494
"C++ IR Dominance": [
9595
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll",
9696
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll"
97+
],
98+
"C++ IR PrintDominance": [
99+
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
100+
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
97101
]
98102
}

cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import cpp
22
import semmle.code.cpp.ir.IR
33

4+
/**
5+
* Holds if `block` consists of an `UnreachedInstruction`.
6+
*
7+
* We avoiding reporting an unreached block as being controlled by a guard. The unreached block
8+
* has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock`
9+
* and the `IRBlock`.
10+
*/
11+
private predicate isUnreachedBlock(IRBlock block) {
12+
block.getFirstInstruction() instanceof UnreachedInstruction
13+
}
14+
415
/**
516
* A Boolean condition in the AST that guards one or more basic blocks. This includes
617
* operands of logical operators but not switch statements.
@@ -215,7 +226,8 @@ private class GuardConditionFromIR extends GuardCondition {
215226
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
216227
exists(IRBlock irb |
217228
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
218-
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled
229+
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled and
230+
not isUnreachedBlock(irb)
219231
)
220232
}
221233
}
@@ -301,6 +313,7 @@ class IRGuardCondition extends Instruction {
301313
* `&&` and `||`. See the detailed explanation on predicate `controls`.
302314
*/
303315
private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) {
316+
not isUnreachedBlock(controlled) and
304317
exists(IRBlock thisblock
305318
| thisblock.getAnInstruction() = this
306319
| exists(IRBlock succ, ConditionalBranchInstruction branch

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@ import Instruction
33
import semmle.code.cpp.ir.implementation.EdgeKind
44
private import Cached
55

6-
class IRBlock extends TIRBlock {
6+
/**
7+
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
8+
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
9+
* sequence.
10+
*
11+
* This class does not contain any members that query the predecessor or successor edges of the
12+
* block. This allows different classes that extend `IRBlockBase` to expose different subsets of
13+
* edges (e.g. ignoring unreachable edges).
14+
*
15+
* Most consumers should use the class `IRBlock`.
16+
*/
17+
class IRBlockBase extends TIRBlock {
718
final string toString() {
819
result = getFirstInstruction(this).toString()
920
}
@@ -59,7 +70,14 @@ class IRBlock extends TIRBlock {
5970
final Function getFunction() {
6071
result = getFirstInstruction(this).getFunction()
6172
}
73+
}
6274

75+
/**
76+
* A basic block with additional information about its predecessor and successor edges. Each edge
77+
* corresponds to the control flow between the last instruction of one block and the first
78+
* instruction of another block.
79+
*/
80+
class IRBlock extends IRBlockBase {
6381
final IRBlock getASuccessor() {
6482
blockSuccessor(this, result)
6583
}

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,7 @@ cached private module Cached {
2525
not oldInstruction instanceof OldIR::PhiInstruction and
2626
hasChiNode(_, oldInstruction)
2727
} or
28-
UnreachedTag(OldInstruction oldInstruction, EdgeKind kind) {
29-
// We need an `Unreached` instruction for the destination of any edge whose predecessor
30-
// instruction is reachable, but whose successor block is not. This should occur only for
31-
// infeasible edges.
32-
exists(OldIR::Instruction succInstruction |
33-
succInstruction = oldInstruction.getSuccessor(kind) and
34-
not succInstruction instanceof OldInstruction
35-
)
36-
}
28+
UnreachedTag()
3729

3830
cached class InstructionTagType extends TInstructionTag {
3931
cached final string toString() {
@@ -133,11 +125,12 @@ cached private module Cached {
133125
resultType = vvar.getType() and
134126
isGLValue = false
135127
) or
136-
exists(OldInstruction oldInstruction, EdgeKind kind |
137-
oldInstruction.getFunction() = func and
138-
tag = UnreachedTag(oldInstruction, kind) and
128+
exists(OldInstruction oldInstruction |
129+
func = oldInstruction.getFunction() and
130+
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) and
131+
tag = UnreachedTag() and
139132
opcode instanceof Opcode::Unreached and
140-
ast = oldInstruction.getSuccessor(kind).getAST() and
133+
ast = func and
141134
resultType instanceof VoidType and
142135
isGLValue = false
143136
)
@@ -213,7 +206,7 @@ cached private module Cached {
213206
exists(Alias::VirtualVariable vvar, OldBlock phiBlock,
214207
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
215208
hasPhiNode(vvar, phiBlock) and
216-
predBlock = phiBlock.getAPredecessor() and
209+
predBlock = phiBlock.getAFeasiblePredecessor() and
217210
instr.getTag() = PhiTag(vvar, phiBlock) and
218211
newPredecessorBlock = getNewBlock(predBlock) and
219212
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
@@ -266,13 +259,22 @@ cached private module Cached {
266259
result = getChiInstruction(getOldInstruction(instruction)) and
267260
kind instanceof GotoEdge
268261
else (
269-
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
270-
or
262+
exists(OldInstruction oldInstruction |
263+
oldInstruction = getOldInstruction(instruction) and
264+
(
265+
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
266+
result.getTag() = UnreachedTag() and
267+
result.getFunction() = instruction.getFunction()
268+
)
269+
else (
270+
result = getNewInstruction(oldInstruction.getSuccessor(kind))
271+
)
272+
)
273+
) or
271274
exists(OldInstruction oldInstruction |
272275
instruction = getChiInstruction(oldInstruction) and
273276
result = getNewInstruction(oldInstruction.getSuccessor(kind))
274-
) or
275-
result.getTag() = UnreachedTag(getOldInstruction(instruction), kind)
277+
)
276278
)
277279
}
278280

@@ -380,7 +382,7 @@ cached private module Cached {
380382

381383
pragma[noinline]
382384
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldBlock block) {
383-
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
385+
variableLiveOnEntryToBlock(vvar, block.getAFeasibleSuccessor())
384386
}
385387

386388
/**
@@ -474,7 +476,7 @@ cached private module Cached {
474476
useRank) or
475477
(
476478
definitionReachesEndOfBlock(vvar, defBlock, defRank,
477-
useBlock.getAPredecessor()) and
479+
useBlock.getAFeasiblePredecessor()) and
478480
not definitionReachesUseWithinBlock(vvar, useBlock, _, useBlock, useRank)
479481
)
480482
)
@@ -518,9 +520,9 @@ cached private module CachedForDebugging {
518520
instr.getTag() = PhiTag(vvar, phiBlock) and
519521
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
520522
) or
521-
exists(OldInstruction oldInstr, EdgeKind kind |
522-
instr.getTag() = UnreachedTag(oldInstr, kind) and
523-
result = "Unreached(" + oldInstr.getUniqueId() + ":" + kind.toString() + ")"
523+
(
524+
instr.getTag() = UnreachedTag() and
525+
result = "Unreached"
524526
)
525527
}
526528

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@ import Instruction
33
import semmle.code.cpp.ir.implementation.EdgeKind
44
private import Cached
55

6-
class IRBlock extends TIRBlock {
6+
/**
7+
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
8+
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
9+
* sequence.
10+
*
11+
* This class does not contain any members that query the predecessor or successor edges of the
12+
* block. This allows different classes that extend `IRBlockBase` to expose different subsets of
13+
* edges (e.g. ignoring unreachable edges).
14+
*
15+
* Most consumers should use the class `IRBlock`.
16+
*/
17+
class IRBlockBase extends TIRBlock {
718
final string toString() {
819
result = getFirstInstruction(this).toString()
920
}
@@ -59,7 +70,14 @@ class IRBlock extends TIRBlock {
5970
final Function getFunction() {
6071
result = getFirstInstruction(this).getFunction()
6172
}
73+
}
6274

75+
/**
76+
* A basic block with additional information about its predecessor and successor edges. Each edge
77+
* corresponds to the control flow between the last instruction of one block and the first
78+
* instruction of another block.
79+
*/
80+
class IRBlock extends IRBlockBase {
6381
final IRBlock getASuccessor() {
6482
blockSuccessor(this, result)
6583
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
private import DominanceInternal
2+
private import ReachableBlockInternal
3+
private import Dominance
4+
import IR
5+
6+
private class DominancePropertyProvider extends IRPropertyProvider {
7+
override string getBlockProperty(IRBlock block, string key) {
8+
exists(IRBlock dominator |
9+
blockImmediatelyDominates(dominator, block) and
10+
key = "ImmediateDominator" and
11+
result = "Block " + dominator.getDisplayIndex().toString()
12+
) or
13+
(
14+
key = "DominanceFrontier" and
15+
result = strictconcat(IRBlock frontierBlock |
16+
frontierBlock = getDominanceFrontier(block) |
17+
frontierBlock.getDisplayIndex().toString(), ", " order by frontierBlock.getDisplayIndex()
18+
)
19+
)
20+
}
21+
}

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,54 @@ private import semmle.code.cpp.ir.internal.IntegerConstant
33
private import IR
44
private import ConstantAnalysis
55

6-
predicate isInfeasibleEdge(IRBlock block, EdgeKind kind) {
7-
exists(ConditionalBranchInstruction instr, int conditionValue |
8-
instr = block.getLastInstruction() and
9-
conditionValue = getValue(getConstantValue(instr.getCondition())) and
6+
predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
7+
exists(int conditionValue |
8+
conditionValue = getValue(getConstantValue(instr.(ConditionalBranchInstruction).getCondition())) and
109
if conditionValue = 0 then
1110
kind instanceof TrueEdge
1211
else
1312
kind instanceof FalseEdge
1413
)
1514
}
1615

17-
IRBlock getAFeasiblePredecessor(IRBlock successor) {
16+
predicate isInfeasibleEdge(IRBlockBase block, EdgeKind kind) {
17+
isInfeasibleInstructionSuccessor(block.getLastInstruction(), kind)
18+
}
19+
20+
private IRBlock getAFeasiblePredecessorBlock(IRBlock successor) {
1821
exists(EdgeKind kind |
1922
result.getSuccessor(kind) = successor and
2023
not isInfeasibleEdge(result, kind)
2124
)
2225
}
2326

24-
predicate isBlockReachable(IRBlock block) {
27+
private predicate isBlockReachable(IRBlock block) {
2528
exists(FunctionIR f |
26-
getAFeasiblePredecessor*(block) = f.getEntryBlock()
29+
getAFeasiblePredecessorBlock*(block) = f.getEntryBlock()
2730
)
2831
}
2932

30-
predicate isInstructionReachable(Instruction instr) {
31-
isBlockReachable(instr.getBlock())
32-
}
33-
34-
class ReachableBlock extends IRBlock {
33+
/**
34+
* An IR block that is reachable from the entry block of the function, considering only feasible
35+
* edges.
36+
*/
37+
class ReachableBlock extends IRBlockBase {
3538
ReachableBlock() {
3639
isBlockReachable(this)
3740
}
41+
42+
final ReachableBlock getAFeasiblePredecessor() {
43+
result = getAFeasiblePredecessorBlock(this)
44+
}
45+
46+
final ReachableBlock getAFeasibleSuccessor() {
47+
this = getAFeasiblePredecessorBlock(result)
48+
}
3849
}
3950

51+
/**
52+
* An instruction that is contained in a reachable block.
53+
*/
4054
class ReachableInstruction extends Instruction {
4155
ReachableInstruction() {
4256
this.getBlock() instanceof ReachableBlock
@@ -51,6 +65,6 @@ module Graph {
5165
}
5266

5367
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
54-
succ = pred.getASuccessor()
68+
succ = pred.getAFeasibleSuccessor()
5569
}
5670
}

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@ import Instruction
33
import semmle.code.cpp.ir.implementation.EdgeKind
44
private import Cached
55

6-
class IRBlock extends TIRBlock {
6+
/**
7+
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
8+
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
9+
* sequence.
10+
*
11+
* This class does not contain any members that query the predecessor or successor edges of the
12+
* block. This allows different classes that extend `IRBlockBase` to expose different subsets of
13+
* edges (e.g. ignoring unreachable edges).
14+
*
15+
* Most consumers should use the class `IRBlock`.
16+
*/
17+
class IRBlockBase extends TIRBlock {
718
final string toString() {
819
result = getFirstInstruction(this).toString()
920
}
@@ -59,7 +70,14 @@ class IRBlock extends TIRBlock {
5970
final Function getFunction() {
6071
result = getFirstInstruction(this).getFunction()
6172
}
73+
}
6274

75+
/**
76+
* A basic block with additional information about its predecessor and successor edges. Each edge
77+
* corresponds to the control flow between the last instruction of one block and the first
78+
* instruction of another block.
79+
*/
80+
class IRBlock extends IRBlockBase {
6381
final IRBlock getASuccessor() {
6482
blockSuccessor(this, result)
6583
}

0 commit comments

Comments
 (0)