Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 38f7ec7

Browse files
committed
C++: Initial implementation of back-edge detection
1 parent aba73f4 commit 38f7ec7

10 files changed

Lines changed: 182 additions & 4 deletions

File tree

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
9090
blockSuccessor(this, result, kind)
9191
}
9292

93+
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
94+
backEdgeSuccessor(this, result, kind)
95+
}
96+
9397
final predicate immediatelyDominates(IRBlock block) {
9498
blockImmediatelyDominates(this, block)
9599
}
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
132136
exists(Instruction predecessor, EdgeKind kind |
133137
instr = predecessor.getSuccessor(kind) and
134138
not kind instanceof GotoEdge
135-
) // Incoming edge is not a GotoEdge
139+
) or // Incoming edge is not a GotoEdge
140+
exists(Instruction predecessor |
141+
instr = predecessor.getBackEdgeSuccessor(_)
142+
) // A back edge enters this instruction
136143
)
137144
}
138145

@@ -184,6 +191,14 @@ private cached module Cached {
184191
)
185192
}
186193

194+
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
exists(Instruction predLast, Instruction succFirst |
196+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197+
succFirst = predLast.getBackEdgeSuccessor(kind) and
198+
succ = MkIRBlock(succFirst)
199+
)
200+
}
201+
187202
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
188203
blockSuccessor(pred, succ, _)
189204
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,16 @@ class Instruction extends Construction::TInstruction {
463463
result = Construction::getInstructionSuccessor(this, kind)
464464
}
465465

466+
/**
467+
* Gets the a _back-edge successor_ of this instruction along the control
468+
* flow edge specified by `kind`. A back edge in the control-flow graph is
469+
* intuitively the edge that goes back around a loop. If all back edges are
470+
* removed from the control-flow graph, it becomes acyclic.
471+
*/
472+
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
473+
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
474+
}
475+
466476
/**
467477
* Gets all direct successors of this instruction.
468478
*/

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ cached private module Cached {
278278
)
279279
}
280280

281+
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
282+
exists(OldInstruction oldInstruction |
283+
oldInstruction = getOldInstruction(instruction) and
284+
result = getNewInstruction(oldInstruction.getBackEdgeSuccessor(kind)) and
285+
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
286+
)
287+
}
288+
281289
cached IRVariable getInstructionVariable(Instruction instruction) {
282290
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
283291
}

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
9090
blockSuccessor(this, result, kind)
9191
}
9292

93+
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
94+
backEdgeSuccessor(this, result, kind)
95+
}
96+
9397
final predicate immediatelyDominates(IRBlock block) {
9498
blockImmediatelyDominates(this, block)
9599
}
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
132136
exists(Instruction predecessor, EdgeKind kind |
133137
instr = predecessor.getSuccessor(kind) and
134138
not kind instanceof GotoEdge
135-
) // Incoming edge is not a GotoEdge
139+
) or // Incoming edge is not a GotoEdge
140+
exists(Instruction predecessor |
141+
instr = predecessor.getBackEdgeSuccessor(_)
142+
) // A back edge enters this instruction
136143
)
137144
}
138145

@@ -184,6 +191,14 @@ private cached module Cached {
184191
)
185192
}
186193

194+
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
exists(Instruction predLast, Instruction succFirst |
196+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197+
succFirst = predLast.getBackEdgeSuccessor(kind) and
198+
succ = MkIRBlock(succFirst)
199+
)
200+
}
201+
187202
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
188203
blockSuccessor(pred, succ, _)
189204
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,16 @@ class Instruction extends Construction::TInstruction {
463463
result = Construction::getInstructionSuccessor(this, kind)
464464
}
465465

466+
/**
467+
* Gets the a _back-edge successor_ of this instruction along the control
468+
* flow edge specified by `kind`. A back edge in the control-flow graph is
469+
* intuitively the edge that goes back around a loop. If all back edges are
470+
* removed from the control-flow graph, it becomes acyclic.
471+
*/
472+
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
473+
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
474+
}
475+
466476
/**
467477
* Gets all direct successors of this instruction.
468478
*/

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ private import semmle.code.cpp.ir.internal.TempVariableTag
55
private import InstructionTag
66
private import TranslatedElement
77
private import TranslatedExpr
8+
private import TranslatedStmt
89
private import TranslatedFunction
910

1011
class InstructionTagType extends TInstructionTag {
@@ -104,6 +105,92 @@ cached private module Cached {
104105
instruction.getTag(), kind)
105106
}
106107

108+
// This predicate has pragma[noopt] because otherwise the `getAChild*` calls
109+
// get joined too early. The join order for the loop cases goes like this:
110+
// - Find all loops of that type (tens of thousands).
111+
// - Find all edges into the start of the loop (x 2).
112+
// - Restrict to edges that originate within the loop (/ 2).
113+
pragma[noopt]
114+
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
115+
// Any edge from within the body of the loop to the condition of the loop
116+
// is a back edge. This includes edges from `continue` and the fall-through
117+
// edge(s) after the last instruction(s) in the body.
118+
exists(TranslatedWhileStmt s |
119+
s instanceof TranslatedWhileStmt and
120+
result = s.getFirstConditionInstruction() and
121+
exists(TranslatedElement inBody, InstructionTag tag |
122+
result = inBody.getInstructionSuccessor(tag, kind) and
123+
exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and
124+
instruction = inBody.getInstruction(tag)
125+
)
126+
)
127+
or
128+
// The back edge should be the (unique) edge from the condition to the
129+
// body. This ensures that it's the back edge that will be pruned in a `do
130+
// { ... } while (0)` statement. Note that all `continue` statements in a
131+
// do-while loop produce forward edges.
132+
exists(TranslatedDoStmt s |
133+
s instanceof TranslatedDoStmt and
134+
exists(TranslatedStmt body | body = s.getBody() | result = body.getFirstInstruction()) and
135+
exists(TranslatedElement inCondition, InstructionTag tag |
136+
result = inCondition.getInstructionSuccessor(tag, kind) and
137+
exists(TranslatedElement condition | condition = s.getCondition() |
138+
inCondition = condition.getAChild*()
139+
) and
140+
instruction = inCondition.getInstruction(tag)
141+
)
142+
)
143+
or
144+
// Any edge from within the body or update of the loop to the condition of
145+
// the loop is a back edge. This includes edges from `continue` and the
146+
// fall-through edge(s) after the last instruction(s) in the body. A `for`
147+
// loop may not have a condition, in which case
148+
// `getFirstConditionInstruction` returns the body instead.
149+
exists(TranslatedForStmt s |
150+
s instanceof TranslatedForStmt and
151+
result = s.getFirstConditionInstruction() and
152+
exists(TranslatedElement inLoop, InstructionTag tag |
153+
result = inLoop.getInstructionSuccessor(tag, kind) and
154+
exists(TranslatedElement bodyOrUpdate |
155+
bodyOrUpdate = s.getBody()
156+
or
157+
bodyOrUpdate = s.getUpdate()
158+
|
159+
inLoop = bodyOrUpdate.getAChild*()
160+
) and
161+
instruction = inLoop.getInstruction(tag)
162+
)
163+
)
164+
or
165+
// As a conservative approximation, any edge out of `goto` is a back edge
166+
// unless it goes strictly forward in the program text. A `goto` whose
167+
// source and target are both inside a macro will be seen as having the
168+
// same location for source and target, so we conservatively assume that
169+
// such a `goto` creates a back edge.
170+
exists(TranslatedElement s, GotoStmt goto |
171+
goto instanceof GotoStmt and
172+
not isStrictlyForwardGoto(goto) and
173+
goto = s.getAST() and
174+
exists(InstructionTag tag |
175+
result = s.getInstructionSuccessor(tag, kind) and
176+
instruction = s.getInstruction(tag)
177+
)
178+
)
179+
}
180+
181+
/** Holds if `goto` jumps strictly forward in the program text. */
182+
private predicate isStrictlyForwardGoto(GotoStmt goto) {
183+
exists(string gotoFile, int gotoLine, string targetFile, int targetLine |
184+
goto.getLocation().hasLocationInfo(gotoFile, gotoLine, _, _, _) and
185+
goto.getTarget().getLocation().hasLocationInfo(targetFile, targetLine, _, _, _) and
186+
targetLine > gotoLine and
187+
// We avoid `=` for equality here since that might tempt the join orderer
188+
// into joining on the file name too early.
189+
gotoFile >= targetFile and
190+
gotoFile <= targetFile
191+
)
192+
}
193+
107194
cached IRVariable getInstructionVariable(Instruction instruction) {
108195
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
109196
instruction.getTag())

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
632632
exists(forStmt.getInitialization())
633633
}
634634

635-
private TranslatedExpr getUpdate() {
635+
TranslatedExpr getUpdate() {
636636
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
637637
}
638638

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
9090
blockSuccessor(this, result, kind)
9191
}
9292

93+
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
94+
backEdgeSuccessor(this, result, kind)
95+
}
96+
9397
final predicate immediatelyDominates(IRBlock block) {
9498
blockImmediatelyDominates(this, block)
9599
}
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
132136
exists(Instruction predecessor, EdgeKind kind |
133137
instr = predecessor.getSuccessor(kind) and
134138
not kind instanceof GotoEdge
135-
) // Incoming edge is not a GotoEdge
139+
) or // Incoming edge is not a GotoEdge
140+
exists(Instruction predecessor |
141+
instr = predecessor.getBackEdgeSuccessor(_)
142+
) // A back edge enters this instruction
136143
)
137144
}
138145

@@ -184,6 +191,14 @@ private cached module Cached {
184191
)
185192
}
186193

194+
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
exists(Instruction predLast, Instruction succFirst |
196+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197+
succFirst = predLast.getBackEdgeSuccessor(kind) and
198+
succ = MkIRBlock(succFirst)
199+
)
200+
}
201+
187202
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
188203
blockSuccessor(pred, succ, _)
189204
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,16 @@ class Instruction extends Construction::TInstruction {
463463
result = Construction::getInstructionSuccessor(this, kind)
464464
}
465465

466+
/**
467+
* Gets the a _back-edge successor_ of this instruction along the control
468+
* flow edge specified by `kind`. A back edge in the control-flow graph is
469+
* intuitively the edge that goes back around a loop. If all back edges are
470+
* removed from the control-flow graph, it becomes acyclic.
471+
*/
472+
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
473+
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
474+
}
475+
466476
/**
467477
* Gets all direct successors of this instruction.
468478
*/

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ cached private module Cached {
278278
)
279279
}
280280

281+
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
282+
exists(OldInstruction oldInstruction |
283+
oldInstruction = getOldInstruction(instruction) and
284+
result = getNewInstruction(oldInstruction.getBackEdgeSuccessor(kind)) and
285+
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
286+
)
287+
}
288+
281289
cached IRVariable getInstructionVariable(Instruction instruction) {
282290
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
283291
}

0 commit comments

Comments
 (0)