mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #812 from jbj/ir-backedge
C++: IR back-edge detection based on TranslatedStmt
This commit is contained in:
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,6 +191,41 @@ private cached module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
forwardEdgeRaw+(pred, pred) and
|
||||
blockSuccessor(pred, succ, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||
*/
|
||||
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||
exists(EdgeKind kind |
|
||||
blockSuccessor(pred, succ, kind) and
|
||||
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||
* `Construction`.
|
||||
*
|
||||
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||
* construction or back-edge detection, and this could cause non-termination
|
||||
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||
* classifies all edges as back edges if they are involved in a loop of
|
||||
* non-back-edges.
|
||||
*/
|
||||
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||
succ = MkIRBlock(succFirst)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -157,6 +157,54 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getFunctionIR() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(FunctionIR f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr = count(Instruction i1, Instruction i2 |
|
||||
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +537,24 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionSuccessor(this, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the a _back-edge successor_ of this instruction along the control
|
||||
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||
* intuitively the edge that goes back around a loop. If all back edges are
|
||||
* removed from the control-flow graph, it becomes acyclic.
|
||||
*/
|
||||
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||
// We don't take these edges from
|
||||
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||
// not been treated to remove any loops that might be left over due to
|
||||
// flaws in the IR construction or back-edge detection.
|
||||
exists(IRBlock block |
|
||||
block = this.getBlock() and
|
||||
this = block.getLastInstruction() and
|
||||
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all direct successors of this instruction.
|
||||
*/
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -279,6 +279,23 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and
|
||||
// There is only one case for the translation into `result` because the
|
||||
// SSA construction never inserts extra instructions _before_ an existing
|
||||
// instruction.
|
||||
getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and
|
||||
// There are two cases for the translation into `instruction` because the
|
||||
// SSA construction might have inserted a chi node _after_
|
||||
// `oldInstruction`, in which case the back edge should come out of the
|
||||
// chi node instead.
|
||||
if hasChiNode(_, oldInstruction)
|
||||
then instruction = getChiInstruction(oldInstruction)
|
||||
else instruction = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,6 +191,41 @@ private cached module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
forwardEdgeRaw+(pred, pred) and
|
||||
blockSuccessor(pred, succ, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||
*/
|
||||
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||
exists(EdgeKind kind |
|
||||
blockSuccessor(pred, succ, kind) and
|
||||
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||
* `Construction`.
|
||||
*
|
||||
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||
* construction or back-edge detection, and this could cause non-termination
|
||||
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||
* classifies all edges as back edges if they are involved in a loop of
|
||||
* non-back-edges.
|
||||
*/
|
||||
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||
succ = MkIRBlock(succFirst)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -157,6 +157,54 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getFunctionIR() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(FunctionIR f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr = count(Instruction i1, Instruction i2 |
|
||||
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +537,24 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionSuccessor(this, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the a _back-edge successor_ of this instruction along the control
|
||||
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||
* intuitively the edge that goes back around a loop. If all back edges are
|
||||
* removed from the control-flow graph, it becomes acyclic.
|
||||
*/
|
||||
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||
// We don't take these edges from
|
||||
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||
// not been treated to remove any loops that might be left over due to
|
||||
// flaws in the IR construction or back-edge detection.
|
||||
exists(IRBlock block |
|
||||
block = this.getBlock() and
|
||||
this = block.getLastInstruction() and
|
||||
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all direct successors of this instruction.
|
||||
*/
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -5,6 +5,7 @@ private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
|
||||
class InstructionTagType extends TInstructionTag {
|
||||
@@ -104,6 +105,88 @@ cached private module Cached {
|
||||
instruction.getTag(), kind)
|
||||
}
|
||||
|
||||
// This predicate has pragma[noopt] because otherwise the `getAChild*` calls
|
||||
// get joined too early. The join order for the loop cases goes like this:
|
||||
// - Find all loops of that type (tens of thousands).
|
||||
// - Find all edges into the start of the loop (x 2).
|
||||
// - Restrict to edges that originate within the loop (/ 2).
|
||||
pragma[noopt]
|
||||
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
// While loop:
|
||||
// Any edge from within the body of the loop to the condition of the loop
|
||||
// is a back edge. This includes edges from `continue` and the fall-through
|
||||
// edge(s) after the last instruction(s) in the body.
|
||||
exists(TranslatedWhileStmt s |
|
||||
s instanceof TranslatedWhileStmt and
|
||||
result = s.getFirstConditionInstruction() and
|
||||
exists(TranslatedElement inBody, InstructionTag tag |
|
||||
result = inBody.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and
|
||||
instruction = inBody.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Do-while loop:
|
||||
// The back edge should be the edge(s) from the condition to the
|
||||
// body. This ensures that it's the back edge that will be pruned in a `do
|
||||
// { ... } while (0)` statement. Note that all `continue` statements in a
|
||||
// do-while loop produce forward edges.
|
||||
exists(TranslatedDoStmt s |
|
||||
s instanceof TranslatedDoStmt and
|
||||
exists(TranslatedStmt body | body = s.getBody() | result = body.getFirstInstruction()) and
|
||||
exists(TranslatedElement inCondition, InstructionTag tag |
|
||||
result = inCondition.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement condition | condition = s.getCondition() |
|
||||
inCondition = condition.getAChild*()
|
||||
) and
|
||||
instruction = inCondition.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
or
|
||||
// For loop:
|
||||
// Any edge from within the body or update of the loop to the condition of
|
||||
// the loop is a back edge. When there is no loop update expression, this
|
||||
// includes edges from `continue` and the fall-through edge(s) after the
|
||||
// last instruction(s) in the body. A for loop may not have a condition, in
|
||||
// which case `getFirstConditionInstruction` returns the body instead.
|
||||
exists(TranslatedForStmt s |
|
||||
s instanceof TranslatedForStmt and
|
||||
result = s.getFirstConditionInstruction() and
|
||||
exists(TranslatedElement inLoop, InstructionTag tag |
|
||||
result = inLoop.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement bodyOrUpdate |
|
||||
bodyOrUpdate = s.getBody()
|
||||
or
|
||||
bodyOrUpdate = s.getUpdate()
|
||||
|
|
||||
inLoop = bodyOrUpdate.getAChild*()
|
||||
) and
|
||||
instruction = inLoop.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Goto statement:
|
||||
// As a conservative approximation, any edge out of `goto` is a back edge
|
||||
// unless it goes strictly forward in the program text. A `goto` whose
|
||||
// source and target are both inside a macro will be seen as having the
|
||||
// same location for source and target, so we conservatively assume that
|
||||
// such a `goto` creates a back edge.
|
||||
exists(TranslatedElement s, GotoStmt goto |
|
||||
goto instanceof GotoStmt and
|
||||
not isStrictlyForwardGoto(goto) and
|
||||
goto = s.getAST() and
|
||||
exists(InstructionTag tag |
|
||||
result = s.getInstructionSuccessor(tag, kind) and
|
||||
instruction = s.getInstruction(tag)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `goto` jumps strictly forward in the program text. */
|
||||
private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
||||
instruction.getTag())
|
||||
|
||||
@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
exists(forStmt.getInitialization())
|
||||
}
|
||||
|
||||
private TranslatedExpr getUpdate() {
|
||||
TranslatedExpr getUpdate() {
|
||||
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
not kind instanceof GotoEdge
|
||||
) // Incoming edge is not a GotoEdge
|
||||
) or // Incoming edge is not a GotoEdge
|
||||
exists(Instruction predecessor |
|
||||
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||
) // A back edge enters this instruction
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,6 +191,41 @@ private cached module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
backEdgeSuccessorRaw(pred, succ, kind)
|
||||
or
|
||||
forwardEdgeRaw+(pred, pred) and
|
||||
blockSuccessor(pred, succ, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||
*/
|
||||
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||
exists(EdgeKind kind |
|
||||
blockSuccessor(pred, succ, kind) and
|
||||
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||
* `Construction`.
|
||||
*
|
||||
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||
* construction or back-edge detection, and this could cause non-termination
|
||||
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||
* classifies all edges as back edges if they are involved in a loop of
|
||||
* non-back-edges.
|
||||
*/
|
||||
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||
exists(Instruction predLast, Instruction succFirst |
|
||||
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||
succ = MkIRBlock(succFirst)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -157,6 +157,54 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getFunctionIR() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(FunctionIR f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr = count(Instruction i1, Instruction i2 |
|
||||
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +537,24 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionSuccessor(this, kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the a _back-edge successor_ of this instruction along the control
|
||||
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||
* intuitively the edge that goes back around a loop. If all back edges are
|
||||
* removed from the control-flow graph, it becomes acyclic.
|
||||
*/
|
||||
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||
// We don't take these edges from
|
||||
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||
// not been treated to remove any loops that might be left over due to
|
||||
// flaws in the IR construction or back-edge detection.
|
||||
exists(IRBlock block |
|
||||
block = this.getBlock() and
|
||||
this = block.getLastInstruction() and
|
||||
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all direct successors of this instruction.
|
||||
*/
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -279,6 +279,23 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and
|
||||
// There is only one case for the translation into `result` because the
|
||||
// SSA construction never inserts extra instructions _before_ an existing
|
||||
// instruction.
|
||||
getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and
|
||||
// There are two cases for the translation into `instruction` because the
|
||||
// SSA construction might have inserted a chi node _after_
|
||||
// `oldInstruction`, in which case the back edge should come out of the
|
||||
// chi node instead.
|
||||
if hasChiNode(_, oldInstruction)
|
||||
then instruction = getChiInstruction(oldInstruction)
|
||||
else instruction = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
@@ -559,47 +559,44 @@ private predicate boundedCastExpr(
|
||||
private predicate boundedInstruction(
|
||||
Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason
|
||||
) {
|
||||
isReducibleCFG(i.getFunction()) and
|
||||
(
|
||||
i instanceof PhiInstruction and
|
||||
forex(PhiOperand op | op = i.getAnOperand() |
|
||||
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
||||
)
|
||||
or
|
||||
i = b.getInstruction(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TNoReason()
|
||||
or
|
||||
exists(Operand mid, int d1, int d2 |
|
||||
boundFlowStep(i, mid, d1, upper) and
|
||||
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
delta = d1 + d2 and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepMul(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof ZeroBound and
|
||||
delta = d*factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepDiv(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
d >= 0 and
|
||||
b instanceof ZeroBound and
|
||||
delta = d / factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastInstruction cast |
|
||||
cast = i and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
i instanceof PhiInstruction and
|
||||
forex(PhiOperand op | op = i.getAnOperand() |
|
||||
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
||||
)
|
||||
or
|
||||
i = b.getInstruction(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TNoReason()
|
||||
or
|
||||
exists(Operand mid, int d1, int d2 |
|
||||
boundFlowStep(i, mid, d1, upper) and
|
||||
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
delta = d1 + d2 and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepMul(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof ZeroBound and
|
||||
delta = d*factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepDiv(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
d >= 0 and
|
||||
b instanceof ZeroBound and
|
||||
delta = d / factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastInstruction cast |
|
||||
cast = i and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -63,24 +63,7 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isReducibleCFG(Function f) {
|
||||
not exists(LabelStmt l, GotoStmt goto |
|
||||
goto.getTarget() = l and
|
||||
l.getLocation().isBefore(goto.getLocation()) and
|
||||
l.getEnclosingFunction() = f
|
||||
) and
|
||||
not exists(LabelStmt ls, Loop l |
|
||||
ls.getParent*() = l and
|
||||
l.getEnclosingFunction() = f
|
||||
) and
|
||||
not exists(SwitchCase cs |
|
||||
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
|
||||
cs.getEnclosingFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
predicate backEdge(PhiInstruction phi, PhiOperand op) {
|
||||
phi.getAnOperand() = op and
|
||||
phi.getBlock().dominates(op.getPredecessorBlock())
|
||||
// TODO: identify backedges during IR construction
|
||||
}
|
||||
phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_)
|
||||
}
|
||||
|
||||
@@ -6782,3 +6782,47 @@ ir.cpp:
|
||||
# 1055| 0: i
|
||||
# 1055| Type = int
|
||||
# 1055| ValueCategory = prvalue(load)
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| params:
|
||||
# 1058| 0: n
|
||||
# 1058| Type = int
|
||||
# 1058| 1: p
|
||||
# 1058| Type = char *
|
||||
# 1058| body: { ... }
|
||||
# 1059| 0: while (...) ...
|
||||
# 1059| 0: ... > ...
|
||||
# 1059| Type = bool
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1059| 0: ... --
|
||||
# 1059| Type = int
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1059| 0: n
|
||||
# 1059| Type = int
|
||||
# 1059| ValueCategory = lvalue
|
||||
# 1059| 1: 0
|
||||
# 1059| Type = int
|
||||
# 1059| Value = 0
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1060| 1: ExprStmt
|
||||
# 1060| 0: ... = ...
|
||||
# 1060| Type = char
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 0: * ...
|
||||
# 1060| Type = char
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 0: ... ++
|
||||
# 1060| Type = char *
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1060| 0: p
|
||||
# 1060| Type = char *
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 1: (char)...
|
||||
# 1060| Conversion = integral conversion
|
||||
# 1060| Type = char
|
||||
# 1060| Value = 0
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1060| expr: 0
|
||||
# 1060| Type = int
|
||||
# 1060| Value = 0
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1061| 1: return ...
|
||||
|
||||
@@ -1116,7 +1116,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1156,7 +1156,7 @@ ir.cpp:
|
||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1175,7 +1175,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 1
|
||||
# 268| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 1
|
||||
# 274| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| Block 3
|
||||
# 278| v3_0(void) = Unreached :
|
||||
@@ -1235,7 +1235,7 @@ ir.cpp:
|
||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1258,7 +1258,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| Block 3
|
||||
# 292| v3_0(void) = Unreached :
|
||||
@@ -1281,7 +1281,7 @@ ir.cpp:
|
||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1310,7 +1310,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1345,7 +1345,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1379,7 +1379,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1441,7 +1441,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1479,7 +1479,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 3
|
||||
# 334| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 333| Block 4
|
||||
# 333| v4_0(void) = Unreached :
|
||||
@@ -1547,7 +1547,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1606,7 +1606,7 @@ ir.cpp:
|
||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4395,7 +4395,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4415,7 +4415,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4431,7 +4431,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4646,3 +4646,46 @@ ir.cpp:
|
||||
|
||||
# 1049| Block 2
|
||||
# 1049| v2_0(void) = Unreached :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| m0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, m3_2
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| m1_6(char) = Store : r1_2, r1_0
|
||||
# 1060| m1_7(unknown) = Chi : m3_0, m1_6
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| m3_0(unknown) = Phi : from 0:m0_1, from 1:m1_7
|
||||
# 1059| m3_1(int) = Phi : from 0:m0_4, from 1:m3_7
|
||||
# 1059| m3_2(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||
# 1059| r3_3(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_4(int) = Load : r3_3, m3_1
|
||||
# 1059| r3_5(int) = Constant[1] :
|
||||
# 1059| r3_6(int) = Sub : r3_4, r3_5
|
||||
# 1059| m3_7(int) = Store : r3_3, r3_6
|
||||
# 1059| r3_8(int) = Constant[0] :
|
||||
# 1059| r3_9(bool) = CompareGT : r3_4, r3_8
|
||||
# 1059| v3_10(void) = ConditionalBranch : r3_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -1055,4 +1055,9 @@ int DoWhileFalse() {
|
||||
return i;
|
||||
}
|
||||
|
||||
void chiNodeAtEndOfLoop(int n, char *p) {
|
||||
while (n-- > 0)
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17
|
||||
|
||||
@@ -1108,7 +1108,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, mu0_2
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| mu1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1146,7 +1146,7 @@ ir.cpp:
|
||||
# 262| r1_8(bool) = CompareGT : r1_6, r1_7
|
||||
# 262| v1_9(void) = ConditionalBranch : r1_8
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1170,7 +1170,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 2
|
||||
# 268| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 2
|
||||
# 274| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 283| Block 3
|
||||
# 283| v3_0(void) = NoOp :
|
||||
@@ -1242,7 +1242,7 @@ ir.cpp:
|
||||
# 287| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 287| r2_4(int) = Add : r2_3, r2_1
|
||||
# 287| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1265,7 +1265,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 296| Block 3
|
||||
# 296| v3_0(void) = NoOp :
|
||||
@@ -1295,7 +1295,7 @@ ir.cpp:
|
||||
# 299| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 299| r2_4(int) = Add : r2_3, r2_1
|
||||
# 299| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1323,7 +1323,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1357,7 +1357,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1390,7 +1390,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, mu0_2
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| mu2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1451,7 +1451,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, mu0_2
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| mu4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1493,7 +1493,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 4
|
||||
# 334| v4_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 339| Block 5
|
||||
# 339| v5_0(void) = NoOp :
|
||||
@@ -1563,7 +1563,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, mu0_2
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| mu3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1619,7 +1619,7 @@ ir.cpp:
|
||||
# 366| r4_4(bool) = CompareGT : r4_2, r4_3
|
||||
# 366| v4_5(void) = ConditionalBranch : r4_4
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4282,7 +4282,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4302,7 +4302,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4318,7 +4318,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4533,7 +4533,7 @@ ir.cpp:
|
||||
# 1053| r1_5(bool) = Constant[0] :
|
||||
# 1053| v1_6(void) = ConditionalBranch : r1_5
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 1055| Block 2
|
||||
# 1055| r2_0(glval<int>) = VariableAddress[#return] :
|
||||
@@ -4544,3 +4544,42 @@ ir.cpp:
|
||||
# 1049| v2_5(void) = ReturnValue : r2_4, mu0_2
|
||||
# 1049| v2_6(void) = UnmodeledUse : mu*
|
||||
# 1049| v2_7(void) = ExitFunction :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| mu0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| mu0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, mu0_2
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| mu1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| r3_0(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_1(int) = Load : r3_0, mu0_2
|
||||
# 1059| r3_2(int) = Constant[1] :
|
||||
# 1059| r3_3(int) = Sub : r3_1, r3_2
|
||||
# 1059| mu3_4(int) = Store : r3_0, r3_3
|
||||
# 1059| r3_5(int) = Constant[0] :
|
||||
# 1059| r3_6(bool) = CompareGT : r3_1, r3_5
|
||||
# 1059| v3_7(void) = ConditionalBranch : r3_6
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
| IR: VirtualMemberFunction | 1 |
|
||||
| IR: WhileStatements | 4 |
|
||||
| IR: WhileStmtWithDeclaration | 8 |
|
||||
| IR: chiNodeAtEndOfLoop | 4 |
|
||||
| IR: designatedInit | 1 |
|
||||
| IR: min | 4 |
|
||||
| IR: operator= | 1 |
|
||||
|
||||
@@ -1109,7 +1109,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1149,7 +1149,7 @@ ir.cpp:
|
||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1168,7 +1168,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 1
|
||||
# 268| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1182,7 +1182,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 1
|
||||
# 274| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1205,7 +1205,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 283| Block 3
|
||||
# 283| v3_0(void) = NoOp :
|
||||
@@ -1231,7 +1231,7 @@ ir.cpp:
|
||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1254,7 +1254,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 296| Block 3
|
||||
# 296| v3_0(void) = NoOp :
|
||||
@@ -1280,7 +1280,7 @@ ir.cpp:
|
||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1309,7 +1309,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1344,7 +1344,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1378,7 +1378,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1440,7 +1440,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1482,7 +1482,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 4
|
||||
# 334| v4_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 339| Block 5
|
||||
# 339| v5_0(void) = NoOp :
|
||||
@@ -1552,7 +1552,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1611,7 +1611,7 @@ ir.cpp:
|
||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4263,7 +4263,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4283,7 +4283,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4299,7 +4299,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4517,3 +4517,44 @@ ir.cpp:
|
||||
|
||||
# 1049| Block 2
|
||||
# 1049| v2_0(void) = Unreached :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, m3_1
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| m3_0(int) = Phi : from 0:m0_4, from 1:m3_6
|
||||
# 1059| m3_1(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||
# 1059| r3_2(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_3(int) = Load : r3_2, m3_0
|
||||
# 1059| r3_4(int) = Constant[1] :
|
||||
# 1059| r3_5(int) = Sub : r3_3, r3_4
|
||||
# 1059| m3_6(int) = Store : r3_2, r3_5
|
||||
# 1059| r3_7(int) = Constant[0] :
|
||||
# 1059| r3_8(bool) = CompareGT : r3_3, r3_7
|
||||
# 1059| v3_9(void) = ConditionalBranch : r3_8
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
||||
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
||||
| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
|
||||
| test.cpp:130:10:130:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
|
||||
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||
@@ -54,3 +55,8 @@
|
||||
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
||||
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
||||
| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
|
||||
| test.cpp:177:10:177:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 1 | false | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:179:10:179:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||
| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||
|
||||
@@ -170,3 +170,19 @@ int test14(int x, int y) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// more interesting bounds with irreducible CFG
|
||||
int test15(int i, int x) {
|
||||
if (x < i) {
|
||||
sink(i); // i >= x + 1
|
||||
} else {
|
||||
sink(i); // i <= x
|
||||
goto inLoop;
|
||||
}
|
||||
for(; i < x; i++) {
|
||||
sink(i); // i <= x - 1
|
||||
inLoop:
|
||||
sink(i); // i <= x
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ test.cpp:
|
||||
# 56| valnum = r5_3
|
||||
# 56| m5_4(char *) = Store : r5_0, r5_3
|
||||
# 56| valnum = r5_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 59| Block 6
|
||||
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
|
||||
@@ -480,7 +480,7 @@ test.cpp:
|
||||
# 62| valnum = r8_3
|
||||
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
|
||||
# 62| valnum = r8_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 63| Block 9
|
||||
# 63| v9_0(void) = NoOp :
|
||||
|
||||
Reference in New Issue
Block a user