mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C++: Remove unreachable IR
This change removes any IR instructions that can be statically proven unreachable. To detect unreachable IR, we first run a simple constant value analysis on the IR. Then, any `ConditionalBranch` with a constant condition has the appropriate edge marked as "infeasible". We define a class `ReachableBlock` as any `IRBlock` with a path from the entry block of the function. SSA construction has been modified to operate only on `ReachableBlock` and `ReachableInstruction`, which ensures that only reachable IR gets translated into SSA form. For any infeasible edge where its predecessor block is reachable, we replace the original target of the branch with an `Unreached` instruction, which lets us preserve the invariant that all `ConditionalBranch` instructions have both a true and a false edge, and allows guard inference to still work. The changes to `SSAConstruction.qll` are not as scary as they look. They are almost entirely a mechanical replacement of `OldIR::IRBlock` with `OldBlock`, which is just an alias for `ReachableBlock`. Note that the `constant_func.ql` test can determine that the two new test functions always return 0. Removing unreachable code helps get rid of some common FPs in IR-based dataflow analysis, especially for constructs like `while(true)`.
This commit is contained in:
@@ -82,5 +82,20 @@
|
||||
"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",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_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",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_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",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/Dominance.qll"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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" } }
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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) {
|
||||
getAFeasiblePredecessor*(block) = block.getFunctionIR().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) {
|
||||
block = block.getFunctionIR().getEntryBlock()
|
||||
}
|
||||
|
||||
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
|
||||
succ = pred.getASuccessor()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis as ConstantAnalysis
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
class Block = Reachability::ReachableBlock;
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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) {
|
||||
getAFeasiblePredecessor*(block) = block.getFunctionIR().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) {
|
||||
block = block.getFunctionIR().getEntryBlock()
|
||||
}
|
||||
|
||||
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
|
||||
succ = pred.getASuccessor()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
class Block = Reachability::ReachableBlock;
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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) {
|
||||
getAFeasiblePredecessor*(block) = block.getFunctionIR().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) {
|
||||
block = block.getFunctionIR().getEntryBlock()
|
||||
}
|
||||
|
||||
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
|
||||
succ = pred.getASuccessor()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -30,3 +30,29 @@ int ReturnConstantPhiLoop(int x) {
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
int UnreachableViaGoto() {
|
||||
goto skip;
|
||||
return 1;
|
||||
skip:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UnreachableIf(bool b) {
|
||||
if (b) {
|
||||
if (false) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (true) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
@@ -1238,22 +1228,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
|
||||
@@ -1292,22 +1277,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
|
||||
@@ -1725,74 +1705,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 +2560,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
|
||||
@@ -4153,32 +4121,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
|
||||
@@ -4629,20 +4589,10 @@ ir.cpp:
|
||||
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
|
||||
# 1025| r0_6(int) = Constant[0] :
|
||||
# 1025| m0_7(int) = Store : r0_5, r0_6
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1021| Block 1
|
||||
# 1021| m1_0(int) = Phi : from 0:m0_7, from 2:m2_2
|
||||
# 1021| r1_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1021| v1_2(void) = ReturnValue : r1_1, m1_0
|
||||
# 1021| v1_3(void) = UnmodeledUse : mu*
|
||||
# 1021| v1_4(void) = ExitFunction :
|
||||
|
||||
# 1023| Block 2
|
||||
# 1023| r2_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1023| r2_1(int) = Constant[1] :
|
||||
# 1023| m2_2(int) = Store : r2_0, r2_1
|
||||
#-----| Goto -> Block 1
|
||||
# 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
|
||||
@@ -4654,11 +4604,11 @@ ir.cpp:
|
||||
# 1029| r0_5(glval<bool>) = VariableAddress[b] :
|
||||
# 1029| r0_6(bool) = Load : r0_5, m0_4
|
||||
# 1029| v0_7(void) = ConditionalBranch : r0_6
|
||||
#-----| False -> Block 5
|
||||
#-----| False -> Block 4
|
||||
#-----| 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| 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*
|
||||
@@ -4667,35 +4617,29 @@ ir.cpp:
|
||||
# 1030| Block 2
|
||||
# 1030| r2_0(bool) = Constant[0] :
|
||||
# 1030| v2_1(void) = ConditionalBranch : r2_0
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 1031| Block 3
|
||||
# 1031| r3_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1031| r3_1(int) = Constant[1] :
|
||||
# 1031| m3_2(int) = Store : r3_0, r3_1
|
||||
# 1034| Block 3
|
||||
# 1034| r3_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1034| r3_1(int) = Constant[0] :
|
||||
# 1034| m3_2(int) = Store : r3_0, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1034| Block 4
|
||||
# 1034| r4_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1034| r4_1(int) = Constant[0] :
|
||||
# 1034| m4_2(int) = Store : r4_0, r4_1
|
||||
# 1038| Block 4
|
||||
# 1038| r4_0(bool) = Constant[1] :
|
||||
# 1038| v4_1(void) = ConditionalBranch : r4_0
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 1039| Block 5
|
||||
# 1039| r5_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1039| r5_1(int) = Constant[0] :
|
||||
# 1039| m5_2(int) = Store : r5_0, r5_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1038| Block 5
|
||||
# 1038| r5_0(bool) = Constant[1] :
|
||||
# 1038| v5_1(void) = ConditionalBranch : r5_0
|
||||
#-----| False -> Block 7
|
||||
#-----| True -> Block 6
|
||||
# 1042| Block 6
|
||||
# 1042| v6_0(void) = Unreached :
|
||||
|
||||
# 1039| Block 6
|
||||
# 1039| r6_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1039| r6_1(int) = Constant[0] :
|
||||
# 1039| m6_2(int) = Store : r6_0, r6_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1042| Block 7
|
||||
# 1042| r7_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1042| r7_1(int) = Constant[1] :
|
||||
# 1042| m7_2(int) = Store : r7_0, r7_1
|
||||
#-----| Goto -> Block 1
|
||||
# 1031| Block 7
|
||||
# 1031| v7_0(void) = Unreached :
|
||||
|
||||
@@ -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,13 +88,13 @@
|
||||
| IR: StaticMemberFunction | 1 |
|
||||
| IR: String | 1 |
|
||||
| IR: StringLiteral | 1 |
|
||||
| IR: Switch | 10 |
|
||||
| IR: Switch | 8 |
|
||||
| IR: TakeReference | 1 |
|
||||
| IR: TryCatch | 15 |
|
||||
| IR: UninitializedVariables | 1 |
|
||||
| IR: UnionInit | 1 |
|
||||
| IR: UnreachableIf | 8 |
|
||||
| IR: UnreachableViaGoto | 3 |
|
||||
| IR: UnreachableViaGoto | 1 |
|
||||
| IR: VarArgUsage | 1 |
|
||||
| IR: VarArgs | 1 |
|
||||
| IR: VirtualMemberFunction | 1 |
|
||||
|
||||
@@ -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
|
||||
@@ -4452,20 +4412,10 @@ ir.cpp:
|
||||
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
|
||||
# 1025| r0_6(int) = Constant[0] :
|
||||
# 1025| m0_7(int) = Store : r0_5, r0_6
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1021| Block 1
|
||||
# 1021| m1_0(int) = Phi : from 0:m0_7, from 2:m2_2
|
||||
# 1021| r1_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1021| v1_2(void) = ReturnValue : r1_1, m1_0
|
||||
# 1021| v1_3(void) = UnmodeledUse : mu*
|
||||
# 1021| v1_4(void) = ExitFunction :
|
||||
|
||||
# 1023| Block 2
|
||||
# 1023| r2_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1023| r2_1(int) = Constant[1] :
|
||||
# 1023| m2_2(int) = Store : r2_0, r2_1
|
||||
#-----| Goto -> Block 1
|
||||
# 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
|
||||
@@ -4477,11 +4427,11 @@ ir.cpp:
|
||||
# 1029| r0_5(glval<bool>) = VariableAddress[b] :
|
||||
# 1029| r0_6(bool) = Load : r0_5, m0_4
|
||||
# 1029| v0_7(void) = ConditionalBranch : r0_6
|
||||
#-----| False -> Block 5
|
||||
#-----| False -> Block 4
|
||||
#-----| 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| 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*
|
||||
@@ -4490,35 +4440,29 @@ ir.cpp:
|
||||
# 1030| Block 2
|
||||
# 1030| r2_0(bool) = Constant[0] :
|
||||
# 1030| v2_1(void) = ConditionalBranch : r2_0
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 1031| Block 3
|
||||
# 1031| r3_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1031| r3_1(int) = Constant[1] :
|
||||
# 1031| m3_2(int) = Store : r3_0, r3_1
|
||||
# 1034| Block 3
|
||||
# 1034| r3_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1034| r3_1(int) = Constant[0] :
|
||||
# 1034| m3_2(int) = Store : r3_0, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1034| Block 4
|
||||
# 1034| r4_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1034| r4_1(int) = Constant[0] :
|
||||
# 1034| m4_2(int) = Store : r4_0, r4_1
|
||||
# 1038| Block 4
|
||||
# 1038| r4_0(bool) = Constant[1] :
|
||||
# 1038| v4_1(void) = ConditionalBranch : r4_0
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 1039| Block 5
|
||||
# 1039| r5_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1039| r5_1(int) = Constant[0] :
|
||||
# 1039| m5_2(int) = Store : r5_0, r5_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1038| Block 5
|
||||
# 1038| r5_0(bool) = Constant[1] :
|
||||
# 1038| v5_1(void) = ConditionalBranch : r5_0
|
||||
#-----| False -> Block 7
|
||||
#-----| True -> Block 6
|
||||
# 1042| Block 6
|
||||
# 1042| v6_0(void) = Unreached :
|
||||
|
||||
# 1039| Block 6
|
||||
# 1039| r6_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1039| r6_1(int) = Constant[0] :
|
||||
# 1039| m6_2(int) = Store : r6_0, r6_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1042| Block 7
|
||||
# 1042| r7_0(glval<int>) = VariableAddress[#return] :
|
||||
# 1042| r7_1(int) = Constant[1] :
|
||||
# 1042| m7_2(int) = Store : r7_0, r7_1
|
||||
#-----| Goto -> Block 1
|
||||
# 1031| Block 7
|
||||
# 1031| v7_0(void) = Unreached :
|
||||
|
||||
Reference in New Issue
Block a user