Merge pull request #812 from jbj/ir-backedge

C++: IR back-edge detection based on TranslatedStmt
This commit is contained in:
Robert Marsh
2019-01-31 11:28:21 -08:00
committed by GitHub
27 changed files with 756 additions and 125 deletions

View File

@@ -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, _)
}

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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())
}

View File

@@ -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, _)
}

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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())

View File

@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
exists(forStmt.getInitialization())
}
private TranslatedExpr getUpdate() {
TranslatedExpr getUpdate() {
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
}

View File

@@ -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, _)
}

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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())
}

View File

@@ -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)
)
}

View File

@@ -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(_)
}

View File

@@ -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 ...

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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 |

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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 |

View File

@@ -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;
}

View File

@@ -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 :