Merge pull request #648 from dave-bartolomeo/dave/UnreachableIR

C++: Remove unreachable IR
This commit is contained in:
Dave Bartolomeo
2018-12-11 20:58:49 -08:00
committed by GitHub
48 changed files with 1417 additions and 538 deletions

View File

@@ -72,5 +72,27 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll"
],
"C++ IR ConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll"
],
"C++ IR PrintConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/PrintConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/PrintConstantAnalysis.qll"
],
"C++ IR ReachableBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll"
],
"C++ IR PrintReachableBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll"
],
"C++ IR Dominance": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll"
]
}

View File

@@ -68,7 +68,8 @@ private newtype TOpcode =
TBufferReadSideEffect() or
TBufferWriteSideEffect() or
TBufferMayWriteSideEffect() or
TChi()
TChi() or
TUnreached()
class Opcode extends TOpcode {
string toString() {
@@ -195,5 +196,6 @@ module Opcode {
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect { override final string toString() { result = "BufferReadSideEffect" } }
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
class Chi extends Opcode, TChi {override final string toString() { result = "Chi" } }
class Chi extends Opcode, TChi { override final string toString() { result = "Chi" } }
class Unreached extends Opcode, TUnreached { override final string toString() { result = "Unreached" } }
}

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -1469,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR

View File

@@ -268,9 +268,10 @@ MemoryAccess getOperandMemoryAccess(Operand operand) {
if exists(IRVariable var, IntValue i |
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, i)
)
then exists(IRVariable var, IntValue i |
then exists(IRVariable var, IntValue i, int size |
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, i) and
result = getVariableMemoryAccess(var, i, operand.getDefinitionInstruction().getResultSize())
result = getVariableMemoryAccess(var, i, size) and
size = operand.getDefinitionInstruction().getResultSize()
)
else (
result = TUnknownMemoryAccess(TUnknownVirtualVariable(operand.getInstruction().getFunctionIR())) and

View File

@@ -4,23 +4,35 @@ private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached newtype TInstructionTag =
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
WrappedInstructionTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
hasPhiNode(vvar, block)
} or
ChiTag(OldIR::Instruction oldInstruction) {
ChiTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
UnreachedTag(OldInstruction oldInstruction, EdgeKind kind) {
// We need an `Unreached` instruction for the destination of any edge whose predecessor
// instruction is reachable, but whose successor block is not. This should occur only for
// infeasible edges.
exists(OldIR::Instruction succInstruction |
succInstruction = oldInstruction.getSuccessor(kind) and
not succInstruction instanceof OldInstruction
)
}
cached class InstructionTagType extends TInstructionTag {
@@ -35,11 +47,11 @@ cached private module Cached {
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
cached OldInstruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
private Instruction getNewInstruction(OldIR::Instruction instr) {
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
@@ -47,21 +59,21 @@ cached private module Cached {
* Gets the chi node corresponding to `instr` if one is present, or the new `Instruction`
* corresponding to `instr` if there is no `Chi` node.
*/
private Instruction getNewFinalInstruction(OldIR::Instruction instr) {
private Instruction getNewFinalInstruction(OldInstruction instr) {
result = getChiInstruction(instr)
or
not exists(getChiInstruction(instr)) and
result = getNewInstruction(instr)
}
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
Alias::VirtualVariable vvar) {
result.getFunction() = func and
result.getAST() = oldBlock.getFirstInstruction().getAST() and
result.getTag() = PhiTag(vvar, oldBlock)
}
private ChiInstruction getChiInstruction (OldIR::Instruction instr) {
private ChiInstruction getChiInstruction (OldInstruction instr) {
hasChiNode(_, instr) and
result.getTag() = ChiTag(instr)
}
@@ -91,8 +103,8 @@ cached private module Cached {
}
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldIR::Instruction instr |
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldInstruction instr |
instr.getFunction() = func and
instr.getOpcode() = opcode and
instr.getAST() = ast and
@@ -103,7 +115,7 @@ cached private module Cached {
else
isGLValue = false
) or
exists(OldIR::IRBlock block, Alias::VirtualVariable vvar |
exists(OldBlock block, Alias::VirtualVariable vvar |
hasPhiNode(vvar, block) and
block.getFunction() = func and
opcode instanceof Opcode::Phi and
@@ -112,7 +124,7 @@ cached private module Cached {
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldIR::Instruction instr, Alias::VirtualVariable vvar |
exists(OldInstruction instr, Alias::VirtualVariable vvar |
hasChiNode(vvar, instr) and
instr.getFunction() = func and
opcode instanceof Opcode::Chi and
@@ -120,11 +132,19 @@ cached private module Cached {
tag = ChiTag(instr) and
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldInstruction oldInstruction, EdgeKind kind |
oldInstruction.getFunction() = func and
tag = UnreachedTag(oldInstruction, kind) and
opcode instanceof Opcode::Unreached and
ast = oldInstruction.getSuccessor(kind).getAST() and
resultType instanceof VoidType and
isGLValue = false
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
Type type) {
exists(OldIR::IRTempVariable var |
var.getFunction() = func and
var.getAST() = ast and
@@ -135,19 +155,20 @@ cached private module Cached {
cached predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction // Phis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
exists(OldInstruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
exists(OldBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
@@ -164,7 +185,7 @@ cached private module Cached {
) or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
exists(OldInstruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
@@ -189,8 +210,8 @@ cached private module Cached {
cached Instruction getPhiInstructionOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock,
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
@@ -205,8 +226,8 @@ cached private module Cached {
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldIR::Instruction oldInstr, OldIR::IRBlock defBlock,
int defRank, int defIndex, OldIR::IRBlock useBlock, int useRank |
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
int defRank, int defIndex, OldBlock useBlock, int useRank |
ChiTag(oldInstr) = chiInstr.getTag() and
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
@@ -220,7 +241,7 @@ cached private module Cached {
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldIR::IRBlock oldBlock |
exists(OldBlock oldBlock |
instr.getTag() = PhiTag(_, oldBlock) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
@@ -247,10 +268,11 @@ cached private module Cached {
else (
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
or
exists(OldIR::Instruction oldInstruction |
exists(OldInstruction oldInstruction |
instruction = getChiInstruction(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
result.getTag() = UnreachedTag(getOldInstruction(instruction), kind)
)
}
@@ -310,29 +332,29 @@ cached private module Cached {
}
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
OldInstruction instr, OldBlock block, int index) {
block.getInstruction(index) = instr and
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
}
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
private predicate hasDefinition(Alias::VirtualVariable vvar, OldBlock block, int index) {
(
hasPhiNode(vvar, block) and
index = -1
) or
exists(Alias::MemoryAccess access, OldIR::Instruction def |
exists(Alias::MemoryAccess access, OldInstruction def |
access = Alias::getResultMemoryAccess(def) and
block.getInstruction(index) = def and
vvar = access.getVirtualVariable()
)
}
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
}
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
int index) {
exists(Alias::MemoryAccess access |
(
access = Alias::getOperandMemoryAccess(use.getAnOperand())
@@ -349,7 +371,7 @@ cached private module Cached {
)
}
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
exists (int index | hasUse(vvar, _, block, index) |
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
) or
@@ -357,7 +379,7 @@ cached private module Cached {
}
pragma[noinline]
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldBlock block) {
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
}
@@ -367,18 +389,18 @@ cached private module Cached {
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private int exitRank(Alias::VirtualVariable vvar, OldBlock block) {
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
}
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
int instructionIndex) {
hasDefinition(vvar, block, instructionIndex) and
defUseRank(vvar, block, rankIndex, instructionIndex)
}
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
int rankIndex, OldIR::Instruction use) {
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
OldInstruction use) {
exists(int index |
hasUse(vvar, use, block, index) and
defUseRank(vvar, block, rankIndex, index)
@@ -389,8 +411,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int defRank, int reachesRank) {
private predicate definitionReachesRank(Alias::VirtualVariable vvar, OldBlock block, int defRank,
int reachesRank) {
hasDefinitionAtRank(vvar, block, defRank, _) and
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
(
@@ -410,8 +432,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
* block `block`.
*/
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock block) {
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
(
(
@@ -421,7 +443,7 @@ cached private module Cached {
variableLiveOnExitFromBlock(vvar, defBlock) and
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
) or
exists(OldIR::IRBlock idom |
exists(OldBlock idom |
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(vvar, idom, block)
)
@@ -429,24 +451,23 @@ cached private module Cached {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
OldIR::IRBlock idom, OldIR::IRBlock block) {
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar, OldBlock idom,
OldBlock block) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
variableLiveOnExitFromBlock(vvar, block) and
not hasDefinition(vvar, block, _)
}
private predicate definitionReachesUseWithinBlock(
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUseWithinBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
defBlock = useBlock and
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
hasUseAtRank(vvar, useBlock, useRank, _) and
definitionReachesRank(vvar, defBlock, defRank, useRank)
}
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUse(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
hasUseAtRank(vvar, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
@@ -459,24 +480,21 @@ cached private module Cached {
)
}
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
exists(OldIR::IRBlock defBlock |
phiBlock = defBlock.dominanceFrontier() and
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
exists(OldBlock defBlock |
phiBlock = Dominance::getDominanceFrontier(defBlock) and
hasDefinition(vvar, defBlock, _) and
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
variableLiveOnEntryToBlock(vvar, phiBlock)
)
}
private predicate hasPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
private predicate hasPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
hasFrontierPhiNode(vvar, phiBlock)
//or ssa_sanitized_custom_phi_node(vvar, block)
}
private predicate hasChiNode(Alias::VirtualVariable vvar,
OldIR::Instruction def) {
private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
exists(Alias::MemoryAccess ma |
ma = Alias::getResultMemoryAccess(def) and
ma.isPartialMemoryAccess() and
@@ -492,13 +510,17 @@ cached private module CachedForDebugging {
}
cached string getInstructionUniqueId(Instruction instr) {
exists(OldIR::Instruction oldInstr |
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
instr.getTag() = PhiTag(vvar, phiBlock) and
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
) or
exists(OldInstruction oldInstr, EdgeKind kind |
instr.getTag() = UnreachedTag(oldInstr, kind) and
result = "Unreached(" + oldInstr.getUniqueId() + ":" + kind.toString() + ")"
)
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import AliasedSSA as Alias

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -1469,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR

View File

@@ -0,0 +1,21 @@
private import DominanceInternal
predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) =
idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block)
predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) {
blockImmediatelyDominates+(dominator, block)
}
predicate blockDominates(Graph::Block dominator, Graph::Block block) {
blockStrictlyDominates(dominator, block) or dominator = block
}
pragma[noinline]
Graph::Block getDominanceFrontier(Graph::Block dominator) {
exists(Graph::Block pred |
Graph::blockSuccessor(pred, result) and
blockDominates(dominator, pred) and
not blockStrictlyDominates(dominator, result)
)
}

View File

@@ -0,0 +1,7 @@
private import ReachableBlock as Reachability
private module ReachabilityGraph = Reachability::Graph;
module Graph {
import Reachability::Graph
class Block = Reachability::ReachableBlock;
}

View File

@@ -0,0 +1,20 @@
private import ReachableBlockInternal
private import ReachableBlock
import IR
private class ReachableBlockPropertyProvider extends IRPropertyProvider {
override string getBlockProperty(IRBlock block, string key) {
(
not block instanceof ReachableBlock and
key = "Unreachable" and
result = "true"
) or
(
exists(EdgeKind kind |
isInfeasibleEdge(block, kind) and
key = "Infeasible(" + kind.toString() + ")" and
result = "true"
)
)
}
}

View File

@@ -0,0 +1,56 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleEdge(IRBlock block, EdgeKind kind) {
exists(ConditionalBranchInstruction instr, int conditionValue |
instr = block.getLastInstruction() and
conditionValue = getValue(getConstantValue(instr.getCondition())) and
if conditionValue = 0 then
kind instanceof TrueEdge
else
kind instanceof FalseEdge
)
}
IRBlock getAFeasiblePredecessor(IRBlock successor) {
exists(EdgeKind kind |
result.getSuccessor(kind) = successor and
not isInfeasibleEdge(result, kind)
)
}
predicate isBlockReachable(IRBlock block) {
exists(FunctionIR f |
getAFeasiblePredecessor*(block) = f.getEntryBlock()
)
}
predicate isInstructionReachable(Instruction instr) {
isBlockReachable(instr.getBlock())
}
class ReachableBlock extends IRBlock {
ReachableBlock() {
isBlockReachable(this)
}
}
class ReachableInstruction extends Instruction {
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock
}
}
module Graph {
predicate isEntryBlock(ReachableBlock block) {
exists(FunctionIR f |
block = f.getEntryBlock()
)
}
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
succ = pred.getASuccessor()
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR
import semmle.code.cpp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -1469,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR

View File

@@ -4,23 +4,35 @@ private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached newtype TInstructionTag =
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
WrappedInstructionTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
hasPhiNode(vvar, block)
} or
ChiTag(OldIR::Instruction oldInstruction) {
ChiTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
UnreachedTag(OldInstruction oldInstruction, EdgeKind kind) {
// We need an `Unreached` instruction for the destination of any edge whose predecessor
// instruction is reachable, but whose successor block is not. This should occur only for
// infeasible edges.
exists(OldIR::Instruction succInstruction |
succInstruction = oldInstruction.getSuccessor(kind) and
not succInstruction instanceof OldInstruction
)
}
cached class InstructionTagType extends TInstructionTag {
@@ -35,11 +47,11 @@ cached private module Cached {
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
cached OldInstruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
private Instruction getNewInstruction(OldIR::Instruction instr) {
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
@@ -47,21 +59,21 @@ cached private module Cached {
* Gets the chi node corresponding to `instr` if one is present, or the new `Instruction`
* corresponding to `instr` if there is no `Chi` node.
*/
private Instruction getNewFinalInstruction(OldIR::Instruction instr) {
private Instruction getNewFinalInstruction(OldInstruction instr) {
result = getChiInstruction(instr)
or
not exists(getChiInstruction(instr)) and
result = getNewInstruction(instr)
}
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
Alias::VirtualVariable vvar) {
result.getFunction() = func and
result.getAST() = oldBlock.getFirstInstruction().getAST() and
result.getTag() = PhiTag(vvar, oldBlock)
}
private ChiInstruction getChiInstruction (OldIR::Instruction instr) {
private ChiInstruction getChiInstruction (OldInstruction instr) {
hasChiNode(_, instr) and
result.getTag() = ChiTag(instr)
}
@@ -91,8 +103,8 @@ cached private module Cached {
}
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldIR::Instruction instr |
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldInstruction instr |
instr.getFunction() = func and
instr.getOpcode() = opcode and
instr.getAST() = ast and
@@ -103,7 +115,7 @@ cached private module Cached {
else
isGLValue = false
) or
exists(OldIR::IRBlock block, Alias::VirtualVariable vvar |
exists(OldBlock block, Alias::VirtualVariable vvar |
hasPhiNode(vvar, block) and
block.getFunction() = func and
opcode instanceof Opcode::Phi and
@@ -112,7 +124,7 @@ cached private module Cached {
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldIR::Instruction instr, Alias::VirtualVariable vvar |
exists(OldInstruction instr, Alias::VirtualVariable vvar |
hasChiNode(vvar, instr) and
instr.getFunction() = func and
opcode instanceof Opcode::Chi and
@@ -120,11 +132,19 @@ cached private module Cached {
tag = ChiTag(instr) and
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldInstruction oldInstruction, EdgeKind kind |
oldInstruction.getFunction() = func and
tag = UnreachedTag(oldInstruction, kind) and
opcode instanceof Opcode::Unreached and
ast = oldInstruction.getSuccessor(kind).getAST() and
resultType instanceof VoidType and
isGLValue = false
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
Type type) {
exists(OldIR::IRTempVariable var |
var.getFunction() = func and
var.getAST() = ast and
@@ -135,19 +155,20 @@ cached private module Cached {
cached predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction // Phis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
exists(OldInstruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
exists(OldBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
@@ -164,7 +185,7 @@ cached private module Cached {
) or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
exists(OldInstruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
@@ -189,8 +210,8 @@ cached private module Cached {
cached Instruction getPhiInstructionOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock,
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
@@ -205,8 +226,8 @@ cached private module Cached {
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldIR::Instruction oldInstr, OldIR::IRBlock defBlock,
int defRank, int defIndex, OldIR::IRBlock useBlock, int useRank |
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
int defRank, int defIndex, OldBlock useBlock, int useRank |
ChiTag(oldInstr) = chiInstr.getTag() and
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
@@ -220,7 +241,7 @@ cached private module Cached {
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldIR::IRBlock oldBlock |
exists(OldBlock oldBlock |
instr.getTag() = PhiTag(_, oldBlock) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
@@ -247,10 +268,11 @@ cached private module Cached {
else (
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
or
exists(OldIR::Instruction oldInstruction |
exists(OldInstruction oldInstruction |
instruction = getChiInstruction(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
result.getTag() = UnreachedTag(getOldInstruction(instruction), kind)
)
}
@@ -310,29 +332,29 @@ cached private module Cached {
}
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
OldInstruction instr, OldBlock block, int index) {
block.getInstruction(index) = instr and
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
}
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
private predicate hasDefinition(Alias::VirtualVariable vvar, OldBlock block, int index) {
(
hasPhiNode(vvar, block) and
index = -1
) or
exists(Alias::MemoryAccess access, OldIR::Instruction def |
exists(Alias::MemoryAccess access, OldInstruction def |
access = Alias::getResultMemoryAccess(def) and
block.getInstruction(index) = def and
vvar = access.getVirtualVariable()
)
}
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
}
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
int index) {
exists(Alias::MemoryAccess access |
(
access = Alias::getOperandMemoryAccess(use.getAnOperand())
@@ -349,7 +371,7 @@ cached private module Cached {
)
}
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
exists (int index | hasUse(vvar, _, block, index) |
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
) or
@@ -357,7 +379,7 @@ cached private module Cached {
}
pragma[noinline]
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldBlock block) {
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
}
@@ -367,18 +389,18 @@ cached private module Cached {
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private int exitRank(Alias::VirtualVariable vvar, OldBlock block) {
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
}
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
int instructionIndex) {
hasDefinition(vvar, block, instructionIndex) and
defUseRank(vvar, block, rankIndex, instructionIndex)
}
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
int rankIndex, OldIR::Instruction use) {
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
OldInstruction use) {
exists(int index |
hasUse(vvar, use, block, index) and
defUseRank(vvar, block, rankIndex, index)
@@ -389,8 +411,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int defRank, int reachesRank) {
private predicate definitionReachesRank(Alias::VirtualVariable vvar, OldBlock block, int defRank,
int reachesRank) {
hasDefinitionAtRank(vvar, block, defRank, _) and
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
(
@@ -410,8 +432,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
* block `block`.
*/
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock block) {
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
(
(
@@ -421,7 +443,7 @@ cached private module Cached {
variableLiveOnExitFromBlock(vvar, defBlock) and
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
) or
exists(OldIR::IRBlock idom |
exists(OldBlock idom |
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(vvar, idom, block)
)
@@ -429,24 +451,23 @@ cached private module Cached {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
OldIR::IRBlock idom, OldIR::IRBlock block) {
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar, OldBlock idom,
OldBlock block) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
variableLiveOnExitFromBlock(vvar, block) and
not hasDefinition(vvar, block, _)
}
private predicate definitionReachesUseWithinBlock(
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUseWithinBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
defBlock = useBlock and
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
hasUseAtRank(vvar, useBlock, useRank, _) and
definitionReachesRank(vvar, defBlock, defRank, useRank)
}
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUse(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
hasUseAtRank(vvar, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
@@ -459,24 +480,21 @@ cached private module Cached {
)
}
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
exists(OldIR::IRBlock defBlock |
phiBlock = defBlock.dominanceFrontier() and
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
exists(OldBlock defBlock |
phiBlock = Dominance::getDominanceFrontier(defBlock) and
hasDefinition(vvar, defBlock, _) and
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
variableLiveOnEntryToBlock(vvar, phiBlock)
)
}
private predicate hasPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
private predicate hasPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
hasFrontierPhiNode(vvar, phiBlock)
//or ssa_sanitized_custom_phi_node(vvar, block)
}
private predicate hasChiNode(Alias::VirtualVariable vvar,
OldIR::Instruction def) {
private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
exists(Alias::MemoryAccess ma |
ma = Alias::getResultMemoryAccess(def) and
ma.isPartialMemoryAccess() and
@@ -492,13 +510,17 @@ cached private module CachedForDebugging {
}
cached string getInstructionUniqueId(Instruction instr) {
exists(OldIR::Instruction oldInstr |
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
instr.getTag() = PhiTag(vvar, phiBlock) and
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
) or
exists(OldInstruction oldInstr, EdgeKind kind |
instr.getTag() = UnreachedTag(oldInstr, kind) and
result = "Unreached(" + oldInstr.getUniqueId() + ":" + kind.toString() + ")"
)
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.raw.IR as OldIR
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import SimpleSSA as Alias

View File

@@ -0,0 +1,21 @@
private import DominanceInternal
predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) =
idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block)
predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) {
blockImmediatelyDominates+(dominator, block)
}
predicate blockDominates(Graph::Block dominator, Graph::Block block) {
blockStrictlyDominates(dominator, block) or dominator = block
}
pragma[noinline]
Graph::Block getDominanceFrontier(Graph::Block dominator) {
exists(Graph::Block pred |
Graph::blockSuccessor(pred, result) and
blockDominates(dominator, pred) and
not blockStrictlyDominates(dominator, result)
)
}

View File

@@ -0,0 +1,7 @@
private import ReachableBlock as Reachability
private module ReachabilityGraph = Reachability::Graph;
module Graph {
import Reachability::Graph
class Block = Reachability::ReachableBlock;
}

View File

@@ -0,0 +1,20 @@
private import ReachableBlockInternal
private import ReachableBlock
import IR
private class ReachableBlockPropertyProvider extends IRPropertyProvider {
override string getBlockProperty(IRBlock block, string key) {
(
not block instanceof ReachableBlock and
key = "Unreachable" and
result = "true"
) or
(
exists(EdgeKind kind |
isInfeasibleEdge(block, kind) and
key = "Infeasible(" + kind.toString() + ")" and
result = "true"
)
)
}
}

View File

@@ -0,0 +1,56 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleEdge(IRBlock block, EdgeKind kind) {
exists(ConditionalBranchInstruction instr, int conditionValue |
instr = block.getLastInstruction() and
conditionValue = getValue(getConstantValue(instr.getCondition())) and
if conditionValue = 0 then
kind instanceof TrueEdge
else
kind instanceof FalseEdge
)
}
IRBlock getAFeasiblePredecessor(IRBlock successor) {
exists(EdgeKind kind |
result.getSuccessor(kind) = successor and
not isInfeasibleEdge(result, kind)
)
}
predicate isBlockReachable(IRBlock block) {
exists(FunctionIR f |
getAFeasiblePredecessor*(block) = f.getEntryBlock()
)
}
predicate isInstructionReachable(Instruction instr) {
isBlockReachable(instr.getBlock())
}
class ReachableBlock extends IRBlock {
ReachableBlock() {
isBlockReachable(this)
}
}
class ReachableInstruction extends Instruction {
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock
}
}
module Graph {
predicate isEntryBlock(ReachableBlock block) {
exists(FunctionIR f |
block = f.getEntryBlock()
)
}
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
succ = pred.getASuccessor()
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis

View File

@@ -102,6 +102,96 @@ IntValue div(IntValue a, IntValue b) {
result = unknown()
}
/**
* Returns `a == b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareEQ(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a = b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a != b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareNE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a != b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a < b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareLT(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a < b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a > b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareGT(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a > b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a <= b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareLE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a <= b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a >= b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareGE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a >= b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Return `-a`. If `a` is unknown, the result is unknown.
*/

View File

@@ -25,7 +25,6 @@ astGuards
| test.c:126:12:126:26 | call to test3_condition |
| test.c:131:7:131:7 | b |
| test.c:137:7:137:7 | 0 |
| test.c:138:9:138:9 | i |
| test.c:146:7:146:8 | ! ... |
| test.c:146:8:146:8 | x |
| test.c:152:10:152:10 | x |
@@ -164,6 +163,7 @@ astGuardsControl
| test.c:42:16:42:21 | ... < ... | true | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | true | 48 | 55 |
| test.c:42:16:42:21 | ... < ... | true | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | false | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | false | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 47 |
@@ -203,9 +203,8 @@ astGuardsControl
| test.c:126:7:126:28 | ... && ... | true | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 |
| test.c:131:7:131:7 | b | true | 131 | 132 |
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
| test.c:137:7:137:7 | 0 | true | 137 | 138 |
| test.c:137:7:137:7 | 0 | true | 138 | 139 |
| test.c:138:9:138:9 | i | true | 138 | 139 |
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
| test.c:146:8:146:8 | x | false | 146 | 147 |
| test.c:152:10:152:10 | x | true | 151 | 152 |
@@ -302,6 +301,7 @@ astGuardsEnsure
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 48 | 55 |
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 47 |
@@ -309,6 +309,7 @@ astGuardsEnsure
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 47 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 48 | 55 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 51 | 53 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | < | test.c:45:20:45:20 | 0 | 1 | 48 | 55 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | test.c:45:20:45:20 | 0 | 1 | 45 | 47 |
@@ -406,7 +407,6 @@ irGuards
| test.c:126:12:126:26 | Call: call to test3_condition |
| test.c:131:7:131:7 | Load: b |
| test.c:137:7:137:7 | Constant: 0 |
| test.c:138:9:138:9 | Load: i |
| test.c:146:8:146:8 | Load: x |
| test.c:152:10:152:10 | Load: x |
| test.c:152:15:152:15 | Load: y |
@@ -521,7 +521,6 @@ irGuardsControl
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | true | 35 | 35 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 46 | 46 |
@@ -563,9 +562,8 @@ irGuardsControl
| test.c:126:7:126:7 | Constant: 1 | true | 127 | 127 |
| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 |
| test.c:131:7:131:7 | Load: b | true | 132 | 132 |
| test.c:137:7:137:7 | Constant: 0 | false | 142 | 142 |
| test.c:137:7:137:7 | Constant: 0 | true | 138 | 138 |
| test.c:137:7:137:7 | Constant: 0 | true | 139 | 139 |
| test.c:138:9:138:9 | Load: i | true | 139 | 139 |
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
@@ -644,13 +642,11 @@ irGuardsEnsure
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | >= | test.c:34:16:34:16 | Load: j | 1 | 35 | 35 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 46 | 46 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 49 | 49 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 52 | 52 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 46 | 46 |

View File

@@ -1,4 +1,3 @@
| test.cpp:6:12:6:17 | test.cpp:21:8:21:9 | IR only |
| test.cpp:66:30:66:36 | test.cpp:71:8:71:9 | AST only |
| test.cpp:89:28:89:34 | test.cpp:90:8:90:14 | AST only |
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |

View File

@@ -2,7 +2,6 @@
| test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:15:8:15:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:21:8:21:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:26:8:26:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:30:8:30:8 | Load: t | test.cpp:35:10:35:15 | Call: call to source |
| test.cpp:31:8:31:8 | Load: c | test.cpp:36:13:36:18 | Call: call to source |

View File

@@ -30,3 +30,31 @@ int ReturnConstantPhiLoop(int x) {
}
return y;
}
int UnreachableViaGoto() {
goto skip;
return 1;
skip:
return 0;
}
int UnreachableIf(bool b) {
int x = 5;
int y = 10;
if (b) {
if (x == y) {
return 1;
}
else {
return 0;
}
}
else {
if (x < y) {
return 0;
}
else {
return 1;
}
}
}

View File

@@ -1,3 +1,5 @@
| constant_func.cpp:1:5:1:18 | IR: ReturnConstant | 7 |
| constant_func.cpp:5:5:5:21 | IR: ReturnConstantPhi | 7 |
| constant_func.cpp:25:5:25:25 | IR: ReturnConstantPhiLoop | 7 |
| constant_func.cpp:34:5:34:22 | IR: UnreachableViaGoto | 0 |
| constant_func.cpp:41:5:41:17 | IR: UnreachableIf | 0 |

View File

@@ -1,29 +1,8 @@
import default
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis
import semmle.code.cpp.ir.internal.IntegerConstant
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}
from FunctionIR funcIR, int value
where
value = getValue(getConstantValue(funcIR.getReturnInstruction().(ReturnValueInstruction).getReturnValue()))

View File

@@ -21,15 +21,49 @@
| -1 * -INT_MAX | 2147483647 |
| -1 - -INT_MAX | 2147483646 |
| -1 - INT_MAX | unknown |
| -3 != 6 | 1 |
| -3 != -3 | 0 |
| -3 != unknown | unknown |
| -3 < 6 | 1 |
| -3 < -3 | 0 |
| -3 < -7 | 0 |
| -3 < unknown | unknown |
| -3 <= 6 | 1 |
| -3 <= -3 | 1 |
| -3 <= -7 | 0 |
| -3 <= unknown | unknown |
| -3 == 6 | 0 |
| -3 == -3 | 1 |
| -3 == unknown | unknown |
| -3 > 6 | 0 |
| -3 > -3 | 0 |
| -3 > -7 | 1 |
| -3 > unknown | unknown |
| -3 >= 6 | 0 |
| -3 >= -3 | 1 |
| -3 >= -7 | 1 |
| -3 >= unknown | unknown |
| -35 / 7 | -5 |
| -35 / 8 | -4 |
| -35 / -7 | 5 |
| -35 / -8 | 4 |
| INT_MAX * INT_MAX | unknown |
| INT_MAX / 0 | unknown |
| unknown != 6 | unknown |
| unknown != unknown | unknown |
| unknown + 5 | unknown |
| unknown + unknown | unknown |
| unknown - 5 | unknown |
| unknown - unknown | unknown |
| unknown / 3 | unknown |
| unknown / unknown | unknown |
| unknown < 6 | unknown |
| unknown < unknown | unknown |
| unknown <= 6 | unknown |
| unknown <= unknown | unknown |
| unknown == 6 | unknown |
| unknown == unknown | unknown |
| unknown > 6 | unknown |
| unknown > unknown | unknown |
| unknown >= 6 | unknown |
| unknown >= unknown | unknown |

View File

@@ -45,5 +45,39 @@ where
expr = "INT_MAX / 0" and res = Ints::div(Ints::maxValue(), 0) or
expr = "0 / unknown" and res = Ints::div(0, Ints::unknown()) or
expr = "unknown / 3" and res = Ints::div(Ints::unknown(), 3) or
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown())
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown()) or
expr = "-3 == -3" and res = Ints::compareEQ(-3, -3) or
expr = "-3 == 6" and res = Ints::compareEQ(-3, 6) or
expr = "-3 == unknown" and res = Ints::compareEQ(-3, Ints::unknown()) or
expr = "unknown == 6" and res = Ints::compareEQ(Ints::unknown(), 6) or
expr = "unknown == unknown" and res = Ints::compareEQ(Ints::unknown(), Ints::unknown()) or
expr = "-3 != -3" and res = Ints::compareNE(-3, -3) or
expr = "-3 != 6" and res = Ints::compareNE(-3, 6) or
expr = "-3 != unknown" and res = Ints::compareNE(-3, Ints::unknown()) or
expr = "unknown != 6" and res = Ints::compareNE(Ints::unknown(), 6) or
expr = "unknown != unknown" and res = Ints::compareNE(Ints::unknown(), Ints::unknown()) or
expr = "-3 < -3" and res = Ints::compareLT(-3, -3) or
expr = "-3 < 6" and res = Ints::compareLT(-3, 6) or
expr = "-3 < -7" and res = Ints::compareLT(-3, -7) or
expr = "-3 < unknown" and res = Ints::compareLT(-3, Ints::unknown()) or
expr = "unknown < 6" and res = Ints::compareLT(Ints::unknown(), 6) or
expr = "unknown < unknown" and res = Ints::compareLT(Ints::unknown(), Ints::unknown()) or
expr = "-3 > -3" and res = Ints::compareGT(-3, -3) or
expr = "-3 > 6" and res = Ints::compareGT(-3, 6) or
expr = "-3 > -7" and res = Ints::compareGT(-3, -7) or
expr = "-3 > unknown" and res = Ints::compareGT(-3, Ints::unknown()) or
expr = "unknown > 6" and res = Ints::compareGT(Ints::unknown(), 6) or
expr = "unknown > unknown" and res = Ints::compareGT(Ints::unknown(), Ints::unknown()) or
expr = "-3 <= -3" and res = Ints::compareLE(-3, -3) or
expr = "-3 <= 6" and res = Ints::compareLE(-3, 6) or
expr = "-3 <= -7" and res = Ints::compareLE(-3, -7) or
expr = "-3 <= unknown" and res = Ints::compareLE(-3, Ints::unknown()) or
expr = "unknown <= 6" and res = Ints::compareLE(Ints::unknown(), 6) or
expr = "unknown <= unknown" and res = Ints::compareLE(Ints::unknown(), Ints::unknown()) or
expr = "-3 >= -3" and res = Ints::compareGE(-3, -3) or
expr = "-3 >= 6" and res = Ints::compareGE(-3, 6) or
expr = "-3 >= -7" and res = Ints::compareGE(-3, -7) or
expr = "-3 >= unknown" and res = Ints::compareGE(-3, Ints::unknown()) or
expr = "unknown >= 6" and res = Ints::compareGE(Ints::unknown(), 6) or
expr = "unknown >= unknown" and res = Ints::compareGE(Ints::unknown(), Ints::unknown())
select expr, resultString(res)

View File

@@ -6668,3 +6668,89 @@ ir.cpp:
# 1018| -1: p
# 1018| Type = Point *
# 1018| ValueCategory = prvalue(load)
# 1021| UnreachableViaGoto() -> int
# 1021| params:
# 1021| body: { ... }
# 1022| 0: goto ...
# 1023| 1: return ...
# 1023| 0: 1
# 1023| Type = int
# 1023| Value = 1
# 1023| ValueCategory = prvalue
# 1024| 2: label ...:
# 1025| 3: return ...
# 1025| 0: 0
# 1025| Type = int
# 1025| Value = 0
# 1025| ValueCategory = prvalue
# 1028| UnreachableIf(bool) -> int
# 1028| params:
# 1028| 0: b
# 1028| Type = bool
# 1028| body: { ... }
# 1029| 0: declaration
# 1029| 0: definition of x
# 1029| Type = int
# 1029| init: initializer for x
# 1029| expr: 5
# 1029| Type = int
# 1029| Value = 5
# 1029| ValueCategory = prvalue
# 1030| 1: declaration
# 1030| 0: definition of y
# 1030| Type = int
# 1030| init: initializer for y
# 1030| expr: 10
# 1030| Type = int
# 1030| Value = 10
# 1030| ValueCategory = prvalue
# 1031| 2: if (...) ...
# 1031| 0: b
# 1031| Type = bool
# 1031| ValueCategory = prvalue(load)
# 1031| 1: { ... }
# 1032| 0: if (...) ...
# 1032| 0: ... == ...
# 1032| Type = bool
# 1032| ValueCategory = prvalue
# 1032| 0: x
# 1032| Type = int
# 1032| ValueCategory = prvalue(load)
# 1032| 1: y
# 1032| Type = int
# 1032| ValueCategory = prvalue(load)
# 1032| 1: { ... }
# 1033| 0: return ...
# 1033| 0: 1
# 1033| Type = int
# 1033| Value = 1
# 1033| ValueCategory = prvalue
# 1035| 2: { ... }
# 1036| 0: return ...
# 1036| 0: 0
# 1036| Type = int
# 1036| Value = 0
# 1036| ValueCategory = prvalue
# 1039| 2: { ... }
# 1040| 0: if (...) ...
# 1040| 0: ... < ...
# 1040| Type = bool
# 1040| ValueCategory = prvalue
# 1040| 0: x
# 1040| Type = int
# 1040| ValueCategory = prvalue(load)
# 1040| 1: y
# 1040| Type = int
# 1040| ValueCategory = prvalue(load)
# 1040| 1: { ... }
# 1041| 0: return ...
# 1041| 0: 0
# 1041| Type = int
# 1041| Value = 0
# 1041| ValueCategory = prvalue
# 1043| 2: { ... }
# 1044| 0: return ...
# 1044| 0: 1
# 1044| Type = int
# 1044| Value = 1
# 1044| ValueCategory = prvalue

View File

@@ -1171,16 +1171,11 @@ ir.cpp:
# 265| mu0_2(unknown) = UnmodeledDefinition :
# 266| r0_3(glval<int>) = VariableAddress[j] :
# 266| m0_4(int) = Uninitialized[j] : r0_3
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 265| Block 1
# 265| v1_0(void) = ReturnVoid :
# 265| v1_1(void) = UnmodeledUse : mu*
# 265| v1_2(void) = ExitFunction :
# 268| Block 2
# 268| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 268| Block 1
# 268| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 272| For_Init() -> void
# 272| Block 0
@@ -1190,16 +1185,11 @@ ir.cpp:
# 273| r0_3(glval<int>) = VariableAddress[i] :
# 273| r0_4(int) = Constant[0] :
# 273| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 272| Block 1
# 272| v1_0(void) = ReturnVoid :
# 272| v1_1(void) = UnmodeledUse : mu*
# 272| v1_2(void) = ExitFunction :
# 274| Block 2
# 274| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 274| Block 1
# 274| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 278| For_Condition() -> void
# 278| Block 0
@@ -1225,10 +1215,7 @@ ir.cpp:
#-----| Goto -> Block 1
# 283| Block 3
# 283| v3_0(void) = NoOp :
# 278| v3_1(void) = ReturnVoid :
# 278| v3_2(void) = UnmodeledUse : mu*
# 278| v3_3(void) = ExitFunction :
# 283| v3_0(void) = Unreached :
# 285| For_Update() -> void
# 285| Block 0
@@ -1238,22 +1225,17 @@ ir.cpp:
# 286| r0_3(glval<int>) = VariableAddress[i] :
# 286| r0_4(int) = Constant[0] :
# 286| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 285| Block 1
# 285| v1_0(void) = ReturnVoid :
# 285| v1_1(void) = UnmodeledUse : mu*
# 285| v1_2(void) = ExitFunction :
# 288| Block 2
# 288| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 288| v2_1(void) = NoOp :
# 287| r2_2(int) = Constant[1] :
# 287| r2_3(glval<int>) = VariableAddress[i] :
# 287| r2_4(int) = Load : r2_3, m2_0
# 287| r2_5(int) = Add : r2_4, r2_2
# 287| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 288| Block 1
# 288| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 288| v1_1(void) = NoOp :
# 287| r1_2(int) = Constant[1] :
# 287| r1_3(glval<int>) = VariableAddress[i] :
# 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
# 292| For_InitCondition() -> void
# 292| Block 0
@@ -1279,10 +1261,7 @@ ir.cpp:
#-----| Goto -> Block 1
# 296| Block 3
# 296| v3_0(void) = NoOp :
# 292| v3_1(void) = ReturnVoid :
# 292| v3_2(void) = UnmodeledUse : mu*
# 292| v3_3(void) = ExitFunction :
# 296| v3_0(void) = Unreached :
# 298| For_InitUpdate() -> void
# 298| Block 0
@@ -1292,22 +1271,17 @@ ir.cpp:
# 299| r0_3(glval<int>) = VariableAddress[i] :
# 299| r0_4(int) = Constant[0] :
# 299| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 298| Block 1
# 298| v1_0(void) = ReturnVoid :
# 298| v1_1(void) = UnmodeledUse : mu*
# 298| v1_2(void) = ExitFunction :
# 300| Block 2
# 300| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 300| v2_1(void) = NoOp :
# 299| r2_2(int) = Constant[1] :
# 299| r2_3(glval<int>) = VariableAddress[i] :
# 299| r2_4(int) = Load : r2_3, m2_0
# 299| r2_5(int) = Add : r2_4, r2_2
# 299| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 300| Block 1
# 300| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 300| v1_1(void) = NoOp :
# 299| r1_2(int) = Constant[1] :
# 299| r1_3(glval<int>) = VariableAddress[i] :
# 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
# 304| For_ConditionUpdate() -> void
# 304| Block 0
@@ -1500,22 +1474,18 @@ ir.cpp:
# 335| r2_2(int) = Constant[5] :
# 335| r2_3(bool) = CompareEQ : r2_1, r2_2
# 335| v2_4(void) = ConditionalBranch : r2_3
#-----| False -> Block 4
#-----| True -> Block 3
#-----| False -> Block 3
#-----| True -> Block 4
# 336| Block 3
# 336| v3_0(void) = NoOp :
#-----| Goto -> Block 4
# 334| Block 4
# 334| v4_0(void) = NoOp :
# 334| Block 3
# 334| v3_0(void) = NoOp :
#-----| Goto -> Block 1
# 336| Block 4
# 336| v4_0(void) = Unreached :
# 339| Block 5
# 339| v5_0(void) = NoOp :
# 333| v5_1(void) = ReturnVoid :
# 333| v5_2(void) = UnmodeledUse : mu*
# 333| v5_3(void) = ExitFunction :
# 339| v5_0(void) = Unreached :
# 341| Dereference(int *) -> int
# 341| Block 0
@@ -1725,74 +1695,62 @@ ir.cpp:
# 386| r0_7(glval<int>) = VariableAddress[x] :
# 386| r0_8(int) = Load : r0_7, m0_4
# 386| v0_9(void) = Switch : r0_8
#-----| Case[-1] -> Block 2
#-----| Case[1] -> Block 3
#-----| Case[2] -> Block 4
#-----| Case[3] -> Block 5
#-----| Case[4] -> Block 6
#-----| Default -> Block 7
#-----| Case[-1] -> Block 1
#-----| Case[1] -> Block 2
#-----| Case[2] -> Block 3
#-----| Case[3] -> Block 4
#-----| Case[4] -> Block 5
#-----| Default -> Block 6
# 387| Block 1
# 387| r1_0(int) = Constant[1234] :
# 387| r1_1(glval<int>) = VariableAddress[y] :
# 387| m1_2(int) = Store : r1_1, r1_0
#-----| Goto -> Block 2
# 389| Block 1
# 389| v1_0(void) = NoOp :
# 390| r1_1(int) = Constant[-1] :
# 390| r1_2(glval<int>) = VariableAddress[y] :
# 390| m1_3(int) = Store : r1_2, r1_1
# 391| v1_4(void) = NoOp :
#-----| Goto -> Block 7
# 389| Block 2
# 389| v2_0(void) = NoOp :
# 390| r2_1(int) = Constant[-1] :
# 390| r2_2(glval<int>) = VariableAddress[y] :
# 390| m2_3(int) = Store : r2_2, r2_1
# 391| v2_4(void) = NoOp :
#-----| Goto -> Block 9
# 393| Block 2
# 393| v2_0(void) = NoOp :
#-----| Goto -> Block 3
# 393| Block 3
# 393| v3_0(void) = NoOp :
#-----| Goto -> Block 4
# 394| Block 3
# 394| v3_0(void) = NoOp :
# 395| r3_1(int) = Constant[1] :
# 395| r3_2(glval<int>) = VariableAddress[y] :
# 395| m3_3(int) = Store : r3_2, r3_1
# 396| v3_4(void) = NoOp :
#-----| Goto -> Block 7
# 394| Block 4
# 394| v4_0(void) = NoOp :
# 395| r4_1(int) = Constant[1] :
# 395| r4_2(glval<int>) = VariableAddress[y] :
# 395| m4_3(int) = Store : r4_2, r4_1
# 396| v4_4(void) = NoOp :
#-----| Goto -> Block 9
# 398| Block 4
# 398| v4_0(void) = NoOp :
# 399| r4_1(int) = Constant[3] :
# 399| r4_2(glval<int>) = VariableAddress[y] :
# 399| m4_3(int) = Store : r4_2, r4_1
#-----| Goto -> Block 5
# 398| Block 5
# 398| v5_0(void) = NoOp :
# 399| r5_1(int) = Constant[3] :
# 399| r5_2(glval<int>) = VariableAddress[y] :
# 399| m5_3(int) = Store : r5_2, r5_1
#-----| Goto -> Block 6
# 400| Block 5
# 400| v5_0(void) = NoOp :
# 401| r5_1(int) = Constant[4] :
# 401| r5_2(glval<int>) = VariableAddress[y] :
# 401| m5_3(int) = Store : r5_2, r5_1
# 402| v5_4(void) = NoOp :
#-----| Goto -> Block 7
# 400| Block 6
# 400| v6_0(void) = NoOp :
# 401| r6_1(int) = Constant[4] :
# 401| r6_2(glval<int>) = VariableAddress[y] :
# 401| m6_3(int) = Store : r6_2, r6_1
# 402| v6_4(void) = NoOp :
#-----| Goto -> Block 9
# 404| Block 6
# 404| v6_0(void) = NoOp :
# 405| r6_1(int) = Constant[0] :
# 405| r6_2(glval<int>) = VariableAddress[y] :
# 405| m6_3(int) = Store : r6_2, r6_1
# 406| v6_4(void) = NoOp :
#-----| Goto -> Block 7
# 404| Block 7
# 404| v7_0(void) = NoOp :
# 405| r7_1(int) = Constant[0] :
# 405| r7_2(glval<int>) = VariableAddress[y] :
# 405| m7_3(int) = Store : r7_2, r7_1
# 406| v7_4(void) = NoOp :
#-----| Goto -> Block 9
# 408| Block 8
# 408| r8_0(int) = Constant[5678] :
# 408| r8_1(glval<int>) = VariableAddress[y] :
# 408| m8_2(int) = Store : r8_1, r8_0
#-----| Goto -> Block 9
# 409| Block 9
# 409| v9_0(void) = NoOp :
# 410| v9_1(void) = NoOp :
# 384| v9_2(void) = ReturnVoid :
# 384| v9_3(void) = UnmodeledUse : mu*
# 384| v9_4(void) = ExitFunction :
# 409| Block 7
# 409| v7_0(void) = NoOp :
# 410| v7_1(void) = NoOp :
# 384| v7_2(void) = ReturnVoid :
# 384| v7_3(void) = UnmodeledUse : mu*
# 384| v7_4(void) = ExitFunction :
# 422| ReturnStruct(Point) -> Point
# 422| Block 0
@@ -2592,7 +2550,7 @@ ir.cpp:
# 560| m0_1(unknown) = AliasedDefinition :
# 560| mu0_2(unknown) = UnmodeledDefinition :
# 560| r0_3(glval<E>) = VariableAddress[e] :
# 560| m0_4(E) = InitializeParameter[e] : r0_3
# 560| mu0_4(E) = InitializeParameter[e] : r0_3
# 561| r0_5(glval<E>) = VariableAddress[e] :
# 561| r0_6(E) = Load : r0_5, mu0_2
# 561| r0_7(int) = Convert : r0_6
@@ -3211,7 +3169,7 @@ ir.cpp:
# 728| r3_2(char *) = Convert : r3_1
# 728| m3_3(char *) = Store : r3_0, r3_2
# 728| v3_4(void) = ThrowValue : r3_0, m3_3
#-----| Exception -> Block 9
#-----| Exception -> Block 6
# 730| Block 4
# 730| r4_0(glval<int>) = VariableAddress[x] :
@@ -3219,83 +3177,57 @@ ir.cpp:
# 730| r4_2(int) = Constant[2] :
# 730| r4_3(bool) = CompareLT : r4_1, r4_2
# 730| v4_4(void) = ConditionalBranch : r4_3
#-----| False -> Block 8
#-----| True -> Block 5
#-----| False -> Block 5
#-----| True -> Block 12
# 731| Block 5
# 731| r5_0(glval<bool>) = VariableAddress[b] :
# 731| r5_1(bool) = Load : r5_0, m0_4
# 731| v5_2(void) = ConditionalBranch : r5_1
#-----| False -> Block 7
#-----| True -> Block 6
# 733| Block 5
# 733| r5_0(int) = Constant[7] :
# 733| r5_1(glval<int>) = VariableAddress[x] :
# 733| m5_2(int) = Store : r5_1, r5_0
#-----| Goto -> Block 11
# 731| Block 6
# 731| r6_0(int) = Constant[7] :
# 731| r6_1(glval<int>) = VariableAddress[#temp731:11] :
# 731| m6_2(int) = Store : r6_1, r6_0
# 731| r6_3(glval<int>) = VariableAddress[#temp731:11] :
# 731| r6_4(int) = Load : r6_3, m6_2
# 731| r6_5(glval<int>) = VariableAddress[x] :
# 731| m6_6(int) = Store : r6_5, r6_4
#-----| Goto -> Block 8
# 735| Block 6
# 735| v6_0(void) = CatchByType[const char *] :
#-----| Exception -> Block 8
#-----| Goto -> Block 7
# 731| Block 7
# 731| r7_0(glval<String>) = VariableAddress[#throw731:19] :
# 731| r7_1(glval<unknown>) = FunctionAddress[String] :
# 731| r7_2(glval<char[14]>) = StringConstant["String object"] :
# 731| r7_3(char *) = Convert : r7_2
# 731| v7_4(void) = Call : r7_1, this:r7_0, r7_3
# 731| m7_5(unknown) = ^CallSideEffect : m0_1
# 731| m7_6(unknown) = Chi : m0_1, m7_5
# 731| v7_7(void) = ThrowValue : r7_0, mu0_2
#-----| Exception -> Block 9
# 733| Block 8
# 733| r8_0(int) = Constant[7] :
# 733| r8_1(glval<int>) = VariableAddress[x] :
# 733| m8_2(int) = Store : r8_1, r8_0
#-----| Goto -> Block 14
# 735| Block 9
# 735| m9_0(unknown) = Phi : from 3:m0_1, from 7:m7_6
# 735| v9_1(void) = CatchByType[const char *] :
#-----| Exception -> Block 11
#-----| Goto -> Block 10
# 735| Block 10
# 735| r10_0(glval<char *>) = VariableAddress[s] :
# 735| m10_1(char *) = InitializeParameter[s] : r10_0
# 736| r10_2(glval<String>) = VariableAddress[#throw736:5] :
# 736| r10_3(glval<unknown>) = FunctionAddress[String] :
# 736| r10_4(glval<char *>) = VariableAddress[s] :
# 736| r10_5(char *) = Load : r10_4, m10_1
# 736| v10_6(void) = Call : r10_3, this:r10_2, r10_5
# 736| m10_7(unknown) = ^CallSideEffect : m9_0
# 736| m10_8(unknown) = Chi : m9_0, m10_7
# 736| v10_9(void) = ThrowValue : r10_2, mu0_2
# 735| Block 7
# 735| r7_0(glval<char *>) = VariableAddress[s] :
# 735| m7_1(char *) = InitializeParameter[s] : r7_0
# 736| r7_2(glval<String>) = VariableAddress[#throw736:5] :
# 736| r7_3(glval<unknown>) = FunctionAddress[String] :
# 736| r7_4(glval<char *>) = VariableAddress[s] :
# 736| r7_5(char *) = Load : r7_4, m7_1
# 736| v7_6(void) = Call : r7_3, this:r7_2, r7_5
# 736| m7_7(unknown) = ^CallSideEffect : m0_1
# 736| m7_8(unknown) = Chi : m0_1, m7_7
# 736| v7_9(void) = ThrowValue : r7_2, mu0_2
#-----| Exception -> Block 2
# 738| Block 11
# 738| v11_0(void) = CatchByType[const String &] :
#-----| Exception -> Block 13
#-----| Goto -> Block 12
# 738| Block 8
# 738| v8_0(void) = CatchByType[const String &] :
#-----| Exception -> Block 10
#-----| Goto -> Block 9
# 738| Block 12
# 738| r12_0(glval<String &>) = VariableAddress[e] :
# 738| m12_1(String &) = InitializeParameter[e] : r12_0
# 738| v12_2(void) = NoOp :
#-----| Goto -> Block 14
# 738| Block 9
# 738| r9_0(glval<String &>) = VariableAddress[e] :
# 738| m9_1(String &) = InitializeParameter[e] : r9_0
# 738| v9_2(void) = NoOp :
#-----| Goto -> Block 11
# 740| Block 13
# 740| v13_0(void) = CatchAny :
# 741| v13_1(void) = ReThrow :
# 740| Block 10
# 740| v10_0(void) = CatchAny :
# 741| v10_1(void) = ReThrow :
#-----| Exception -> Block 2
# 743| Block 14
# 743| v14_0(void) = NoOp :
# 724| v14_1(void) = ReturnVoid :
# 743| Block 11
# 743| v11_0(void) = NoOp :
# 724| v11_1(void) = ReturnVoid :
#-----| Goto -> Block 1
# 731| Block 12
# 731| v12_0(void) = Unreached :
# 745| Base::Base(const Base &) -> void
# 745| Block 0
# 745| v0_0(void) = EnterFunction :
@@ -4153,32 +4085,24 @@ ir.cpp:
# 906| r0_8(glval<int>) = VariableAddress[b] :
# 906| r0_9(bool) = Constant[1] :
# 906| v0_10(void) = ConditionalBranch : r0_9
#-----| False -> Block 3
#-----| True -> Block 2
#-----| False -> Block 2
#-----| True -> Block 1
# 906| Block 1
# 906| m1_0(int) = Phi : from 2:m2_3, from 3:m3_3
# 906| r1_1(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_2(int) = Load : r1_1, m1_0
# 906| m1_3(int) = Store : r0_8, r1_2
# 907| v1_4(void) = NoOp :
# 904| v1_5(void) = ReturnVoid :
# 904| v1_6(void) = UnmodeledUse : mu*
# 904| v1_7(void) = ExitFunction :
# 906| r1_0(glval<int>) = VariableAddress[x] :
# 906| r1_1(int) = Load : r1_0, m0_4
# 906| r1_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m1_3(int) = Store : r1_2, r1_1
# 906| r1_4(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_5(int) = Load : r1_4, m1_3
# 906| m1_6(int) = Store : r0_8, r1_5
# 907| v1_7(void) = NoOp :
# 904| v1_8(void) = ReturnVoid :
# 904| v1_9(void) = UnmodeledUse : mu*
# 904| v1_10(void) = ExitFunction :
# 906| Block 2
# 906| r2_0(glval<int>) = VariableAddress[x] :
# 906| r2_1(int) = Load : r2_0, m0_4
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m2_3(int) = Store : r2_2, r2_1
#-----| Goto -> Block 1
# 906| Block 3
# 906| r3_0(glval<int>) = VariableAddress[x] :
# 906| r3_1(int) = Load : r3_0, m0_4
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m3_3(int) = Store : r3_2, r3_1
#-----| Goto -> Block 1
# 906| v2_0(void) = Unreached :
# 940| OperatorNew() -> void
# 940| Block 0
@@ -4618,3 +4542,82 @@ ir.cpp:
# 1005| v6_13(void) = ReturnValue : r6_12, m6_11
# 1005| v6_14(void) = UnmodeledUse : mu*
# 1005| v6_15(void) = ExitFunction :
# 1021| UnreachableViaGoto() -> int
# 1021| Block 0
# 1021| v0_0(void) = EnterFunction :
# 1021| m0_1(unknown) = AliasedDefinition :
# 1021| mu0_2(unknown) = UnmodeledDefinition :
# 1022| v0_3(void) = NoOp :
# 1024| v0_4(void) = NoOp :
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
# 1025| r0_6(int) = Constant[0] :
# 1025| m0_7(int) = Store : r0_5, r0_6
# 1021| r0_8(glval<int>) = VariableAddress[#return] :
# 1021| v0_9(void) = ReturnValue : r0_8, m0_7
# 1021| v0_10(void) = UnmodeledUse : mu*
# 1021| v0_11(void) = ExitFunction :
# 1028| UnreachableIf(bool) -> int
# 1028| Block 0
# 1028| v0_0(void) = EnterFunction :
# 1028| m0_1(unknown) = AliasedDefinition :
# 1028| mu0_2(unknown) = UnmodeledDefinition :
# 1028| r0_3(glval<bool>) = VariableAddress[b] :
# 1028| m0_4(bool) = InitializeParameter[b] : r0_3
# 1029| r0_5(glval<int>) = VariableAddress[x] :
# 1029| r0_6(int) = Constant[5] :
# 1029| m0_7(int) = Store : r0_5, r0_6
# 1030| r0_8(glval<int>) = VariableAddress[y] :
# 1030| r0_9(int) = Constant[10] :
# 1030| m0_10(int) = Store : r0_8, r0_9
# 1031| r0_11(glval<bool>) = VariableAddress[b] :
# 1031| r0_12(bool) = Load : r0_11, m0_4
# 1031| v0_13(void) = ConditionalBranch : r0_12
#-----| False -> Block 4
#-----| True -> Block 2
# 1028| Block 1
# 1028| m1_0(int) = Phi : from 3:m3_2, from 5:m5_2
# 1028| r1_1(glval<int>) = VariableAddress[#return] :
# 1028| v1_2(void) = ReturnValue : r1_1, m1_0
# 1028| v1_3(void) = UnmodeledUse : mu*
# 1028| v1_4(void) = ExitFunction :
# 1032| Block 2
# 1032| r2_0(glval<int>) = VariableAddress[x] :
# 1032| r2_1(int) = Load : r2_0, m0_7
# 1032| r2_2(glval<int>) = VariableAddress[y] :
# 1032| r2_3(int) = Load : r2_2, m0_10
# 1032| r2_4(bool) = CompareEQ : r2_1, r2_3
# 1032| v2_5(void) = ConditionalBranch : r2_4
#-----| False -> Block 3
#-----| True -> Block 6
# 1036| Block 3
# 1036| r3_0(glval<int>) = VariableAddress[#return] :
# 1036| r3_1(int) = Constant[0] :
# 1036| m3_2(int) = Store : r3_0, r3_1
#-----| Goto -> Block 1
# 1040| Block 4
# 1040| r4_0(glval<int>) = VariableAddress[x] :
# 1040| r4_1(int) = Load : r4_0, m0_7
# 1040| r4_2(glval<int>) = VariableAddress[y] :
# 1040| r4_3(int) = Load : r4_2, m0_10
# 1040| r4_4(bool) = CompareLT : r4_1, r4_3
# 1040| v4_5(void) = ConditionalBranch : r4_4
#-----| False -> Block 7
#-----| True -> Block 5
# 1041| Block 5
# 1041| r5_0(glval<int>) = VariableAddress[#return] :
# 1041| r5_1(int) = Constant[0] :
# 1041| m5_2(int) = Store : r5_0, r5_1
#-----| Goto -> Block 1
# 1033| Block 6
# 1033| v6_0(void) = Unreached :
# 1044| Block 7
# 1044| v7_0(void) = Unreached :

View File

@@ -1018,4 +1018,32 @@ int ChiPhiNode(Point *p, bool which1, bool which2) {
return p->x + p->y;
}
int UnreachableViaGoto() {
goto skip;
return 1;
skip:
return 0;
}
int UnreachableIf(bool b) {
int x = 5;
int y = 10;
if (b) {
if (x == y) {
return 1;
}
else {
return 0;
}
}
else {
if (x < y) {
return 0;
}
else {
return 1;
}
}
}
// semmle-extractor-options: -std=c++17

View File

@@ -4420,3 +4420,96 @@ ir.cpp:
# 1005| v6_12(void) = ReturnValue : r6_11, mu0_2
# 1005| v6_13(void) = UnmodeledUse : mu*
# 1005| v6_14(void) = ExitFunction :
# 1021| UnreachableViaGoto() -> int
# 1021| Block 0
# 1021| v0_0(void) = EnterFunction :
# 1021| mu0_1(unknown) = AliasedDefinition :
# 1021| mu0_2(unknown) = UnmodeledDefinition :
# 1022| v0_3(void) = NoOp :
# 1024| v0_4(void) = NoOp :
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
# 1025| r0_6(int) = Constant[0] :
# 1025| mu0_7(int) = Store : r0_5, r0_6
#-----| Goto -> Block 1
# 1021| Block 1
# 1021| r1_0(glval<int>) = VariableAddress[#return] :
# 1021| v1_1(void) = ReturnValue : r1_0, mu0_2
# 1021| v1_2(void) = UnmodeledUse : mu*
# 1021| v1_3(void) = ExitFunction :
# 1023| Block 2
# 1023| r2_0(glval<int>) = VariableAddress[#return] :
# 1023| r2_1(int) = Constant[1] :
# 1023| mu2_2(int) = Store : r2_0, r2_1
#-----| Goto -> Block 1
# 1028| UnreachableIf(bool) -> int
# 1028| Block 0
# 1028| v0_0(void) = EnterFunction :
# 1028| mu0_1(unknown) = AliasedDefinition :
# 1028| mu0_2(unknown) = UnmodeledDefinition :
# 1028| r0_3(glval<bool>) = VariableAddress[b] :
# 1028| mu0_4(bool) = InitializeParameter[b] : r0_3
# 1029| r0_5(glval<int>) = VariableAddress[x] :
# 1029| r0_6(int) = Constant[5] :
# 1029| mu0_7(int) = Store : r0_5, r0_6
# 1030| r0_8(glval<int>) = VariableAddress[y] :
# 1030| r0_9(int) = Constant[10] :
# 1030| mu0_10(int) = Store : r0_8, r0_9
# 1031| r0_11(glval<bool>) = VariableAddress[b] :
# 1031| r0_12(bool) = Load : r0_11, mu0_2
# 1031| v0_13(void) = ConditionalBranch : r0_12
#-----| False -> Block 5
#-----| True -> Block 2
# 1028| Block 1
# 1028| r1_0(glval<int>) = VariableAddress[#return] :
# 1028| v1_1(void) = ReturnValue : r1_0, mu0_2
# 1028| v1_2(void) = UnmodeledUse : mu*
# 1028| v1_3(void) = ExitFunction :
# 1032| Block 2
# 1032| r2_0(glval<int>) = VariableAddress[x] :
# 1032| r2_1(int) = Load : r2_0, mu0_2
# 1032| r2_2(glval<int>) = VariableAddress[y] :
# 1032| r2_3(int) = Load : r2_2, mu0_2
# 1032| r2_4(bool) = CompareEQ : r2_1, r2_3
# 1032| v2_5(void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 1033| Block 3
# 1033| r3_0(glval<int>) = VariableAddress[#return] :
# 1033| r3_1(int) = Constant[1] :
# 1033| mu3_2(int) = Store : r3_0, r3_1
#-----| Goto -> Block 1
# 1036| Block 4
# 1036| r4_0(glval<int>) = VariableAddress[#return] :
# 1036| r4_1(int) = Constant[0] :
# 1036| mu4_2(int) = Store : r4_0, r4_1
#-----| Goto -> Block 1
# 1040| Block 5
# 1040| r5_0(glval<int>) = VariableAddress[x] :
# 1040| r5_1(int) = Load : r5_0, mu0_2
# 1040| r5_2(glval<int>) = VariableAddress[y] :
# 1040| r5_3(int) = Load : r5_2, mu0_2
# 1040| r5_4(bool) = CompareLT : r5_1, r5_3
# 1040| v5_5(void) = ConditionalBranch : r5_4
#-----| False -> Block 7
#-----| True -> Block 6
# 1041| Block 6
# 1041| r6_0(glval<int>) = VariableAddress[#return] :
# 1041| r6_1(int) = Constant[0] :
# 1041| mu6_2(int) = Store : r6_0, r6_1
#-----| Goto -> Block 1
# 1044| Block 7
# 1044| r7_0(glval<int>) = VariableAddress[#return] :
# 1044| r7_1(int) = Constant[1] :
# 1044| mu7_2(int) = Store : r7_0, r7_1
#-----| Goto -> Block 1

View File

@@ -22,7 +22,7 @@
| IR: Conditional | 4 |
| IR: Conditional_LValue | 4 |
| IR: Conditional_Void | 4 |
| IR: ConstantConditions | 4 |
| IR: ConstantConditions | 3 |
| IR: Constants | 1 |
| IR: Continue | 6 |
| IR: DeclareObject | 1 |
@@ -45,12 +45,12 @@
| IR: For_ConditionUpdate | 4 |
| IR: For_Continue_NoUpdate | 6 |
| IR: For_Continue_Update | 6 |
| IR: For_Empty | 3 |
| IR: For_Init | 3 |
| IR: For_Empty | 2 |
| IR: For_Init | 2 |
| IR: For_InitCondition | 4 |
| IR: For_InitConditionUpdate | 4 |
| IR: For_InitUpdate | 3 |
| IR: For_Update | 3 |
| IR: For_InitUpdate | 2 |
| IR: For_Update | 2 |
| IR: Func | 1 |
| IR: FuncPtrConversions | 1 |
| IR: FunctionReferences | 1 |
@@ -88,11 +88,13 @@
| IR: StaticMemberFunction | 1 |
| IR: String | 1 |
| IR: StringLiteral | 1 |
| IR: Switch | 10 |
| IR: Switch | 8 |
| IR: TakeReference | 1 |
| IR: TryCatch | 15 |
| IR: TryCatch | 13 |
| IR: UninitializedVariables | 1 |
| IR: UnionInit | 1 |
| IR: UnreachableIf | 8 |
| IR: UnreachableViaGoto | 1 |
| IR: VarArgUsage | 1 |
| IR: VarArgs | 1 |
| IR: VirtualMemberFunction | 1 |

View File

@@ -1164,16 +1164,11 @@ ir.cpp:
# 265| mu0_2(unknown) = UnmodeledDefinition :
# 266| r0_3(glval<int>) = VariableAddress[j] :
# 266| m0_4(int) = Uninitialized[j] : r0_3
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 265| Block 1
# 265| v1_0(void) = ReturnVoid :
# 265| v1_1(void) = UnmodeledUse : mu*
# 265| v1_2(void) = ExitFunction :
# 268| Block 2
# 268| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 268| Block 1
# 268| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 272| For_Init() -> void
# 272| Block 0
@@ -1183,16 +1178,11 @@ ir.cpp:
# 273| r0_3(glval<int>) = VariableAddress[i] :
# 273| r0_4(int) = Constant[0] :
# 273| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 272| Block 1
# 272| v1_0(void) = ReturnVoid :
# 272| v1_1(void) = UnmodeledUse : mu*
# 272| v1_2(void) = ExitFunction :
# 274| Block 2
# 274| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 274| Block 1
# 274| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 278| For_Condition() -> void
# 278| Block 0
@@ -1231,22 +1221,17 @@ ir.cpp:
# 286| r0_3(glval<int>) = VariableAddress[i] :
# 286| r0_4(int) = Constant[0] :
# 286| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 285| Block 1
# 285| v1_0(void) = ReturnVoid :
# 285| v1_1(void) = UnmodeledUse : mu*
# 285| v1_2(void) = ExitFunction :
# 288| Block 2
# 288| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 288| v2_1(void) = NoOp :
# 287| r2_2(int) = Constant[1] :
# 287| r2_3(glval<int>) = VariableAddress[i] :
# 287| r2_4(int) = Load : r2_3, m2_0
# 287| r2_5(int) = Add : r2_4, r2_2
# 287| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 288| Block 1
# 288| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 288| v1_1(void) = NoOp :
# 287| r1_2(int) = Constant[1] :
# 287| r1_3(glval<int>) = VariableAddress[i] :
# 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
# 292| For_InitCondition() -> void
# 292| Block 0
@@ -1285,22 +1270,17 @@ ir.cpp:
# 299| r0_3(glval<int>) = VariableAddress[i] :
# 299| r0_4(int) = Constant[0] :
# 299| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 298| Block 1
# 298| v1_0(void) = ReturnVoid :
# 298| v1_1(void) = UnmodeledUse : mu*
# 298| v1_2(void) = ExitFunction :
# 300| Block 2
# 300| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 300| v2_1(void) = NoOp :
# 299| r2_2(int) = Constant[1] :
# 299| r2_3(glval<int>) = VariableAddress[i] :
# 299| r2_4(int) = Load : r2_3, m2_0
# 299| r2_5(int) = Add : r2_4, r2_2
# 299| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 300| Block 1
# 300| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 300| v1_1(void) = NoOp :
# 299| r1_2(int) = Constant[1] :
# 299| r1_3(glval<int>) = VariableAddress[i] :
# 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
# 304| For_ConditionUpdate() -> void
# 304| Block 0
@@ -1713,74 +1693,62 @@ ir.cpp:
# 386| r0_7(glval<int>) = VariableAddress[x] :
# 386| r0_8(int) = Load : r0_7, m0_4
# 386| v0_9(void) = Switch : r0_8
#-----| Case[-1] -> Block 2
#-----| Case[1] -> Block 3
#-----| Case[2] -> Block 4
#-----| Case[3] -> Block 5
#-----| Case[4] -> Block 6
#-----| Default -> Block 7
#-----| Case[-1] -> Block 1
#-----| Case[1] -> Block 2
#-----| Case[2] -> Block 3
#-----| Case[3] -> Block 4
#-----| Case[4] -> Block 5
#-----| Default -> Block 6
# 387| Block 1
# 387| r1_0(int) = Constant[1234] :
# 387| r1_1(glval<int>) = VariableAddress[y] :
# 387| m1_2(int) = Store : r1_1, r1_0
#-----| Goto -> Block 2
# 389| Block 1
# 389| v1_0(void) = NoOp :
# 390| r1_1(int) = Constant[-1] :
# 390| r1_2(glval<int>) = VariableAddress[y] :
# 390| m1_3(int) = Store : r1_2, r1_1
# 391| v1_4(void) = NoOp :
#-----| Goto -> Block 7
# 389| Block 2
# 389| v2_0(void) = NoOp :
# 390| r2_1(int) = Constant[-1] :
# 390| r2_2(glval<int>) = VariableAddress[y] :
# 390| m2_3(int) = Store : r2_2, r2_1
# 391| v2_4(void) = NoOp :
#-----| Goto -> Block 9
# 393| Block 2
# 393| v2_0(void) = NoOp :
#-----| Goto -> Block 3
# 393| Block 3
# 393| v3_0(void) = NoOp :
#-----| Goto -> Block 4
# 394| Block 3
# 394| v3_0(void) = NoOp :
# 395| r3_1(int) = Constant[1] :
# 395| r3_2(glval<int>) = VariableAddress[y] :
# 395| m3_3(int) = Store : r3_2, r3_1
# 396| v3_4(void) = NoOp :
#-----| Goto -> Block 7
# 394| Block 4
# 394| v4_0(void) = NoOp :
# 395| r4_1(int) = Constant[1] :
# 395| r4_2(glval<int>) = VariableAddress[y] :
# 395| m4_3(int) = Store : r4_2, r4_1
# 396| v4_4(void) = NoOp :
#-----| Goto -> Block 9
# 398| Block 4
# 398| v4_0(void) = NoOp :
# 399| r4_1(int) = Constant[3] :
# 399| r4_2(glval<int>) = VariableAddress[y] :
# 399| m4_3(int) = Store : r4_2, r4_1
#-----| Goto -> Block 5
# 398| Block 5
# 398| v5_0(void) = NoOp :
# 399| r5_1(int) = Constant[3] :
# 399| r5_2(glval<int>) = VariableAddress[y] :
# 399| m5_3(int) = Store : r5_2, r5_1
#-----| Goto -> Block 6
# 400| Block 5
# 400| v5_0(void) = NoOp :
# 401| r5_1(int) = Constant[4] :
# 401| r5_2(glval<int>) = VariableAddress[y] :
# 401| m5_3(int) = Store : r5_2, r5_1
# 402| v5_4(void) = NoOp :
#-----| Goto -> Block 7
# 400| Block 6
# 400| v6_0(void) = NoOp :
# 401| r6_1(int) = Constant[4] :
# 401| r6_2(glval<int>) = VariableAddress[y] :
# 401| m6_3(int) = Store : r6_2, r6_1
# 402| v6_4(void) = NoOp :
#-----| Goto -> Block 9
# 404| Block 6
# 404| v6_0(void) = NoOp :
# 405| r6_1(int) = Constant[0] :
# 405| r6_2(glval<int>) = VariableAddress[y] :
# 405| m6_3(int) = Store : r6_2, r6_1
# 406| v6_4(void) = NoOp :
#-----| Goto -> Block 7
# 404| Block 7
# 404| v7_0(void) = NoOp :
# 405| r7_1(int) = Constant[0] :
# 405| r7_2(glval<int>) = VariableAddress[y] :
# 405| m7_3(int) = Store : r7_2, r7_1
# 406| v7_4(void) = NoOp :
#-----| Goto -> Block 9
# 408| Block 8
# 408| r8_0(int) = Constant[5678] :
# 408| r8_1(glval<int>) = VariableAddress[y] :
# 408| m8_2(int) = Store : r8_1, r8_0
#-----| Goto -> Block 9
# 409| Block 9
# 409| v9_0(void) = NoOp :
# 410| v9_1(void) = NoOp :
# 384| v9_2(void) = ReturnVoid :
# 384| v9_3(void) = UnmodeledUse : mu*
# 384| v9_4(void) = ExitFunction :
# 409| Block 7
# 409| v7_0(void) = NoOp :
# 410| v7_1(void) = NoOp :
# 384| v7_2(void) = ReturnVoid :
# 384| v7_3(void) = UnmodeledUse : mu*
# 384| v7_4(void) = ExitFunction :
# 422| ReturnStruct(Point) -> Point
# 422| Block 0
@@ -4007,32 +3975,24 @@ ir.cpp:
# 906| r0_8(glval<int>) = VariableAddress[b] :
# 906| r0_9(bool) = Constant[1] :
# 906| v0_10(void) = ConditionalBranch : r0_9
#-----| False -> Block 3
#-----| True -> Block 2
#-----| False -> Block 2
#-----| True -> Block 1
# 906| Block 1
# 906| m1_0(int) = Phi : from 2:m2_3, from 3:m3_3
# 906| r1_1(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_2(int) = Load : r1_1, m1_0
# 906| m1_3(int) = Store : r0_8, r1_2
# 907| v1_4(void) = NoOp :
# 904| v1_5(void) = ReturnVoid :
# 904| v1_6(void) = UnmodeledUse : mu*
# 904| v1_7(void) = ExitFunction :
# 906| r1_0(glval<int>) = VariableAddress[x] :
# 906| r1_1(int) = Load : r1_0, m0_4
# 906| r1_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m1_3(int) = Store : r1_2, r1_1
# 906| r1_4(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_5(int) = Load : r1_4, m1_3
# 906| m1_6(int) = Store : r0_8, r1_5
# 907| v1_7(void) = NoOp :
# 904| v1_8(void) = ReturnVoid :
# 904| v1_9(void) = UnmodeledUse : mu*
# 904| v1_10(void) = ExitFunction :
# 906| Block 2
# 906| r2_0(glval<int>) = VariableAddress[x] :
# 906| r2_1(int) = Load : r2_0, m0_4
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m2_3(int) = Store : r2_2, r2_1
#-----| Goto -> Block 1
# 906| Block 3
# 906| r3_0(glval<int>) = VariableAddress[x] :
# 906| r3_1(int) = Load : r3_0, m0_4
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m3_3(int) = Store : r3_2, r3_1
#-----| Goto -> Block 1
# 906| v2_0(void) = Unreached :
# 940| OperatorNew() -> void
# 940| Block 0
@@ -4441,3 +4401,88 @@ ir.cpp:
# 1005| v6_12(void) = ReturnValue : r6_11, m6_10
# 1005| v6_13(void) = UnmodeledUse : mu*
# 1005| v6_14(void) = ExitFunction :
# 1021| UnreachableViaGoto() -> int
# 1021| Block 0
# 1021| v0_0(void) = EnterFunction :
# 1021| mu0_1(unknown) = AliasedDefinition :
# 1021| mu0_2(unknown) = UnmodeledDefinition :
# 1022| v0_3(void) = NoOp :
# 1024| v0_4(void) = NoOp :
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
# 1025| r0_6(int) = Constant[0] :
# 1025| m0_7(int) = Store : r0_5, r0_6
# 1021| r0_8(glval<int>) = VariableAddress[#return] :
# 1021| v0_9(void) = ReturnValue : r0_8, m0_7
# 1021| v0_10(void) = UnmodeledUse : mu*
# 1021| v0_11(void) = ExitFunction :
# 1028| UnreachableIf(bool) -> int
# 1028| Block 0
# 1028| v0_0(void) = EnterFunction :
# 1028| mu0_1(unknown) = AliasedDefinition :
# 1028| mu0_2(unknown) = UnmodeledDefinition :
# 1028| r0_3(glval<bool>) = VariableAddress[b] :
# 1028| m0_4(bool) = InitializeParameter[b] : r0_3
# 1029| r0_5(glval<int>) = VariableAddress[x] :
# 1029| r0_6(int) = Constant[5] :
# 1029| m0_7(int) = Store : r0_5, r0_6
# 1030| r0_8(glval<int>) = VariableAddress[y] :
# 1030| r0_9(int) = Constant[10] :
# 1030| m0_10(int) = Store : r0_8, r0_9
# 1031| r0_11(glval<bool>) = VariableAddress[b] :
# 1031| r0_12(bool) = Load : r0_11, m0_4
# 1031| v0_13(void) = ConditionalBranch : r0_12
#-----| False -> Block 5
#-----| True -> Block 2
# 1028| Block 1
# 1028| m1_0(int) = Phi : from 3:m3_2, from 4:m4_2, from 6:m6_2, from 7:m7_2
# 1028| r1_1(glval<int>) = VariableAddress[#return] :
# 1028| v1_2(void) = ReturnValue : r1_1, m1_0
# 1028| v1_3(void) = UnmodeledUse : mu*
# 1028| v1_4(void) = ExitFunction :
# 1032| Block 2
# 1032| r2_0(glval<int>) = VariableAddress[x] :
# 1032| r2_1(int) = Load : r2_0, m0_7
# 1032| r2_2(glval<int>) = VariableAddress[y] :
# 1032| r2_3(int) = Load : r2_2, m0_10
# 1032| r2_4(bool) = CompareEQ : r2_1, r2_3
# 1032| v2_5(void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 1033| Block 3
# 1033| r3_0(glval<int>) = VariableAddress[#return] :
# 1033| r3_1(int) = Constant[1] :
# 1033| m3_2(int) = Store : r3_0, r3_1
#-----| Goto -> Block 1
# 1036| Block 4
# 1036| r4_0(glval<int>) = VariableAddress[#return] :
# 1036| r4_1(int) = Constant[0] :
# 1036| m4_2(int) = Store : r4_0, r4_1
#-----| Goto -> Block 1
# 1040| Block 5
# 1040| r5_0(glval<int>) = VariableAddress[x] :
# 1040| r5_1(int) = Load : r5_0, m0_7
# 1040| r5_2(glval<int>) = VariableAddress[y] :
# 1040| r5_3(int) = Load : r5_2, m0_10
# 1040| r5_4(bool) = CompareLT : r5_1, r5_3
# 1040| v5_5(void) = ConditionalBranch : r5_4
#-----| False -> Block 7
#-----| True -> Block 6
# 1041| Block 6
# 1041| r6_0(glval<int>) = VariableAddress[#return] :
# 1041| r6_1(int) = Constant[0] :
# 1041| m6_2(int) = Store : r6_0, r6_1
#-----| Goto -> Block 1
# 1044| Block 7
# 1044| r7_0(glval<int>) = VariableAddress[#return] :
# 1044| r7_1(int) = Constant[1] :
# 1044| m7_2(int) = Store : r7_0, r7_1
#-----| Goto -> Block 1

View File

@@ -499,7 +499,6 @@
| test.c:367:15:367:17 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:368:5:368:21 | Store: ... = ... | positive strictlyPositive |
| test.c:368:10:368:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:368:10:368:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:368:10:368:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:368:11:368:11 | Load: x | positive |
| test.c:368:11:368:13 | Add: ... + ... | positive strictlyPositive |
@@ -508,7 +507,6 @@
| test.c:369:5:369:36 | Store: ... = ... | positive strictlyPositive |
| test.c:369:10:369:36 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:369:10:369:36 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:369:10:369:36 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:369:10:369:36 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:369:11:369:30 | Convert: (unsigned char)... | positive |
| test.c:369:27:369:27 | Load: x | positive |
@@ -518,7 +516,6 @@
| test.c:370:5:370:38 | Store: ... = ... | positive strictlyPositive |
| test.c:370:10:370:38 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:370:10:370:38 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:370:10:370:38 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:370:10:370:38 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:370:11:370:30 | Convert: (unsigned char)... | positive |
| test.c:370:27:370:27 | Load: x | positive |
@@ -528,7 +525,6 @@
| test.c:371:5:371:39 | Store: ... = ... | positive strictlyPositive |
| test.c:371:10:371:39 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:371:10:371:39 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:371:10:371:39 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:371:10:371:39 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:371:11:371:31 | Convert: (unsigned short)... | positive |
| test.c:371:28:371:28 | Load: x | positive |
@@ -591,7 +587,6 @@
| test.c:384:12:384:14 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:385:5:385:21 | Store: ... = ... | positive strictlyPositive |
| test.c:385:10:385:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:385:10:385:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:385:10:385:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:385:11:385:11 | Load: x | positive strictlyPositive |
| test.c:385:11:385:15 | Sub: ... - ... | positive |
@@ -599,7 +594,6 @@
| test.c:385:21:385:21 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:386:5:386:21 | Store: ... = ... | positive strictlyPositive |
| test.c:386:10:386:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:386:10:386:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:386:10:386:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:386:11:386:11 | Load: x | positive strictlyPositive |
| test.c:386:11:386:15 | Sub: ... - ... | positive |
@@ -608,7 +602,6 @@
| test.c:387:5:387:38 | Store: ... = ... | positive strictlyPositive |
| test.c:387:10:387:38 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:387:10:387:38 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:387:10:387:38 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:387:10:387:38 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:387:11:387:32 | Convert: (unsigned char)... | positive |
| test.c:387:27:387:27 | Load: x | positive strictlyPositive |