diff --git a/config/identical-files.json b/config/identical-files.json index 57fdd85e543..0a69ba5bc56 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -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" ] } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index ce2d5be7e14..973aed120d2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.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" } } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index c325e77509c..8514c6db1e1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -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() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 7fc7f69ec74..d956421a268 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -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. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 76899995426..f5492fdb54f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -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() + ")" ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index 5a4d3779e1e..5eebc0b9516 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/Dominance.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/Dominance.qll new file mode 100644 index 00000000000..7521407530a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/Dominance.qll @@ -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) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/PrintReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/PrintReachableBlock.qll new file mode 100644 index 00000000000..1af465d6ec9 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/PrintReachableBlock.qll @@ -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" + ) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlock.qll new file mode 100644 index 00000000000..985ca631ae1 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlock.qll @@ -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() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlockInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..139609dfffa --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -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 \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index c325e77509c..8514c6db1e1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -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() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 7fc7f69ec74..d956421a268 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -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. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll new file mode 100644 index 00000000000..7521407530a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll @@ -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) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/DominanceInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/DominanceInternal.qll new file mode 100644 index 00000000000..dfe9b52f1a4 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/DominanceInternal.qll @@ -0,0 +1,7 @@ +private import ReachableBlock as Reachability +private module ReachabilityGraph = Reachability::Graph; + +module Graph { + import Reachability::Graph + class Block = Reachability::ReachableBlock; +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll new file mode 100644 index 00000000000..1af465d6ec9 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll @@ -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" + ) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll new file mode 100644 index 00000000000..985ca631ae1 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll @@ -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() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..e58552be10f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll @@ -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 \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index c325e77509c..8514c6db1e1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -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() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 7fc7f69ec74..d956421a268 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -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. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 76899995426..f5492fdb54f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -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() + ")" ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index f5ee42e9573..dc19a8130d9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll new file mode 100644 index 00000000000..7521407530a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll @@ -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) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll new file mode 100644 index 00000000000..dfe9b52f1a4 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll @@ -0,0 +1,7 @@ +private import ReachableBlock as Reachability +private module ReachabilityGraph = Reachability::Graph; + +module Graph { + import Reachability::Graph + class Block = Reachability::ReachableBlock; +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll new file mode 100644 index 00000000000..1af465d6ec9 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll @@ -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" + ) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll new file mode 100644 index 00000000000..985ca631ae1 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll @@ -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() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..bcaaaaf69d0 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -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 \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.cpp b/cpp/ql/test/library-tests/ir/constant_func/constant_func.cpp index 107d79da46b..851675c4f03 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.cpp +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.cpp @@ -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; + } + } +} diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected index 7aebdccfdfb..87363c7d5b6 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.expected @@ -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 | diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.expected index d2129156d2d..22be5703f95 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.expected @@ -1171,16 +1171,11 @@ ir.cpp: # 265| mu0_2(unknown) = UnmodeledDefinition : # 266| r0_3(glval) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = VariableAddress[e] : -# 560| m0_4(E) = InitializeParameter[e] : r0_3 +# 560| mu0_4(E) = InitializeParameter[e] : r0_3 # 561| r0_5(glval) = 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) = 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) = 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) = VariableAddress[x] : +# 906| r1_1(int) = Load : r1_0, m0_4 +# 906| r1_2(glval) = VariableAddress[#temp906:11] : +# 906| m1_3(int) = Store : r1_2, r1_1 +# 906| r1_4(glval) = 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) = VariableAddress[x] : -# 906| r2_1(int) = Load : r2_0, m0_4 -# 906| r2_2(glval) = VariableAddress[#temp906:11] : -# 906| m2_3(int) = Store : r2_2, r2_1 -#-----| Goto -> Block 1 - -# 906| Block 3 -# 906| r3_0(glval) = VariableAddress[x] : -# 906| r3_1(int) = Load : r3_0, m0_4 -# 906| r3_2(glval) = 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) = 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) = 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) = VariableAddress[#return] : -# 1023| r2_1(int) = Constant[1] : -# 1023| m2_2(int) = Store : r2_0, r2_1 -#-----| Goto -> Block 1 +# 1021| r0_8(glval) = 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) = 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) = 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) = VariableAddress[#return] : -# 1031| r3_1(int) = Constant[1] : -# 1031| m3_2(int) = Store : r3_0, r3_1 +# 1034| Block 3 +# 1034| r3_0(glval) = 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) = 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) = 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) = 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) = 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 : diff --git a/cpp/ql/test/library-tests/ir/ir/ssa_block_count.expected b/cpp/ql/test/library-tests/ir/ir/ssa_block_count.expected index b646183d290..0c644ba447c 100644 --- a/cpp/ql/test/library-tests/ir/ir/ssa_block_count.expected +++ b/cpp/ql/test/library-tests/ir/ir/ssa_block_count.expected @@ -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 | diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ir.expected index d60c8c38799..adbfdf03306 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ir.expected @@ -1164,16 +1164,11 @@ ir.cpp: # 265| mu0_2(unknown) = UnmodeledDefinition : # 266| r0_3(glval) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = 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) = VariableAddress[x] : +# 906| r1_1(int) = Load : r1_0, m0_4 +# 906| r1_2(glval) = VariableAddress[#temp906:11] : +# 906| m1_3(int) = Store : r1_2, r1_1 +# 906| r1_4(glval) = 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) = VariableAddress[x] : -# 906| r2_1(int) = Load : r2_0, m0_4 -# 906| r2_2(glval) = VariableAddress[#temp906:11] : -# 906| m2_3(int) = Store : r2_2, r2_1 -#-----| Goto -> Block 1 - -# 906| Block 3 -# 906| r3_0(glval) = VariableAddress[x] : -# 906| r3_1(int) = Load : r3_0, m0_4 -# 906| r3_2(glval) = 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) = 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) = 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) = VariableAddress[#return] : -# 1023| r2_1(int) = Constant[1] : -# 1023| m2_2(int) = Store : r2_0, r2_1 -#-----| Goto -> Block 1 +# 1021| r0_8(glval) = 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) = 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) = 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) = VariableAddress[#return] : -# 1031| r3_1(int) = Constant[1] : -# 1031| m3_2(int) = Store : r3_0, r3_1 +# 1034| Block 3 +# 1034| r3_0(glval) = 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) = 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) = 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) = 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) = 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 :