Merge pull request #16907 from MathiasVP/phi-escape-5

C++: Add a new `MemoryLocation` to represent sets of `Allocation`s
This commit is contained in:
Mathias Vorreiter Pedersen
2024-07-17 15:44:04 +01:00
committed by GitHub
29 changed files with 3170 additions and 235 deletions

View File

@@ -40,7 +40,8 @@ predicate ignoreInstruction(Instruction instr) {
instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction
instr instanceof ReturnIndirectionInstruction or
instr instanceof UninitializedGroupInstruction
)
}

View File

@@ -13,7 +13,8 @@ private newtype TMemoryAccessKind =
TPhiMemoryAccess() or
TUnmodeledMemoryAccess() or
TChiTotalMemoryAccess() or
TChiPartialMemoryAccess()
TChiPartialMemoryAccess() or
TGroupedMemoryAccess()
/**
* Describes the set of memory locations memory accessed by a memory operand or
@@ -99,3 +100,11 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
override string toString() { result = "chi(partial)" }
}
/**
* The result of an `UninitializedGroup` instruction, which initializes a set of
* allocations that are each assigned the same virtual variable.
*/
class GroupedMemoryAccess extends MemoryAccessKind, TGroupedMemoryAccess {
override string toString() { result = "group" }
}

View File

@@ -89,6 +89,7 @@ private newtype TOpcode =
TSizedBufferMayWriteSideEffect() or
TInitializeDynamicAllocation() or
TChi() or
TUninitializedGroup() or
TInlineAsm() or
TUnreached() or
TNewObj()
@@ -1237,6 +1238,17 @@ module Opcode {
}
}
/**
* The `Opcode` for a `UninitializedGroup`.
*
* See the `UninitializedGroupInstruction` documentation for more details.
*/
class UninitializedGroup extends Opcode, TUninitializedGroup {
final override string toString() { result = "UninitializedGroup" }
override GroupedMemoryAccess getWriteMemoryAccess() { any() }
}
/**
* The `Opcode` for an `InlineAsmInstruction`.
*

View File

@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -106,8 +106,7 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction and
not operand.getUse() instanceof ReturnIndirectionInstruction and
not operand instanceof PhiInputOperand
not operand.getUse() instanceof ReturnIndirectionInstruction
}
/**
@@ -191,6 +190,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
// A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
)
or
operand = instr.(PhiInstruction).getAnInputOperand() and
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
// through the back edge of a loop (or through recursion).
bitOffset = Ints::unknown()
}
private predicate operandEscapesNonReturn(Operand operand) {
@@ -212,9 +216,6 @@ private predicate operandEscapesNonReturn(Operand operand) {
or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand)
}
@@ -236,9 +237,6 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction
or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
}
private predicate operandReturned(Operand operand, IntValue bitOffset) {

View File

@@ -101,6 +101,8 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
final override predicate isAlwaysAllocatedOnStack() { none() }
final override predicate alwaysEscapes() { none() }
final IRAutomaticVariable getIRVariable() { result = var }
}
class DynamicAllocation extends Allocation, TDynamicAllocation {

View File

@@ -8,6 +8,7 @@ private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import AliasConfiguration
private import codeql.util.Boolean
private class IntValue = Ints::IntValue;
@@ -16,49 +17,196 @@ private predicate isIndirectOrBufferMemoryAccess(MemoryAccessKind kind) {
kind instanceof BufferMemoryAccess
}
private predicate hasResultMemoryAccess(
Instruction instr, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
private predicate hasMemoryAccess(
AddressOperand addrOperand, Allocation var, IntValue startBitOffset, boolean grouped
) {
exists(AddressOperand addrOperand |
addrOperand = instr.getResultAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
)
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
if strictcount(Allocation alloc | addressOperandAllocationAndOffset(addrOperand, alloc, _)) > 1
then grouped = true
else grouped = false
}
private predicate hasResultMemoryAccess(
AddressOperand address, Instruction instr, Allocation var, IRType type,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
boolean isMayAccess, boolean grouped
) {
address = instr.getResultAddressOperand() and
hasMemoryAccess(address, var, startBitOffset, grouped) and
languageType = instr.getResultLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
}
private predicate hasOperandMemoryAccess(
MemoryOperand operand, Allocation var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
AddressOperand address, MemoryOperand operand, Allocation var, IRType type,
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
boolean isMayAccess, boolean grouped
) {
exists(AddressOperand addrOperand |
addrOperand = operand.getAddressOperand() and
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
address = operand.getAddressOperand() and
hasMemoryAccess(address, var, startBitOffset, grouped) and
languageType = operand.getLanguageType() and
type = languageType.getIRType() and
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown()
}
private Allocation getAnAllocation(AddressOperand address) {
hasResultMemoryAccess(address, _, result, _, _, _, _, _, true) or
hasOperandMemoryAccess(address, _, result, _, _, _, _, _, true)
}
private module AllocationSet0 =
QlBuiltins::InternSets<AddressOperand, Allocation, getAnAllocation/1>;
/**
* A set of allocations containing at least 2 elements.
*/
private class NonSingletonSets extends AllocationSet0::Set {
NonSingletonSets() { strictcount(Allocation var | this.contains(var)) > 1 }
/** Gets an allocation from this set. */
Allocation getAnAllocation() { this.contains(result) }
/** Gets the string representation of this set. */
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
}
/** Holds the instersection of `s1` and `s2` is non-empty. */
private predicate hasOverlappingElement(NonSingletonSets s1, NonSingletonSets s2) {
exists(Allocation var |
s1.contains(var) and
s2.contains(var)
)
}
private module AllocationSet =
QlBuiltins::EquivalenceRelation<NonSingletonSets, hasOverlappingElement/2>;
/**
* Holds if `var` is created by the AST element `e`. Furthermore, the value `d`
* represents which branch of the `Allocation` type `var` is from.
*/
private predicate allocationAst(Allocation var, @element e, int d) {
var.(VariableAllocation).getIRVariable().getAst() = e and d = 0
or
var.(IndirectParameterAllocation).getIRVariable().getAst() = e and d = 1
or
var.(DynamicAllocation).getABaseInstruction().getAst() = e and d = 2
}
/** Holds if `x = y` and `x` is an AST element that creates an `Allocation`. */
private predicate id(@element x, @element y) {
allocationAst(_, x, _) and
x = y
}
private predicate idOf(@element x, int y) = equivalenceRelation(id/2)(x, y)
/** Gets a unique integer representation of `var`. */
private int getUniqueAllocationId(Allocation var) {
exists(int r, @element e, int d |
allocationAst(var, e, d) and
idOf(e, r) and
result = 3 * r + d
)
}
/**
* An equivalence class of a set of allocations.
*
* Any `VariableGroup` will be completely disjunct from any other
* `VariableGroup`.
*/
class VariableGroup extends AllocationSet::EquivalenceClass {
/** Gets the location of this set. */
final Location getLocation() { result = this.getIRFunction().getLocation() }
/** Gets the enclosing `IRFunction` of this set. */
final IRFunction getIRFunction() {
result = unique( | | this.getAnAllocation().getEnclosingIRFunction())
}
/** Gets the type of elements contained in this set. */
final Language::LanguageType getType() {
strictcount(Language::LanguageType langType |
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
)
) = 1 and
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, result, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, result, _, _, _, true)
)
or
strictcount(Language::LanguageType langType |
exists(Allocation var | var = this.getAnAllocation() |
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
)
) > 1 and
result = any(IRUnknownType type).getCanonicalLanguageType()
}
/** Gets an allocation of this set. */
final Allocation getAnAllocation() {
exists(AllocationSet0::Set set |
this = AllocationSet::getEquivalenceClass(set) and
set.contains(result)
)
}
/** Gets a unique string representing this set. */
final private string getUniqueId() {
result = strictconcat(getUniqueAllocationId(this.getAnAllocation()).toString(), ",")
}
/**
* Gets the order that this set should be initialized in.
*
* Note: This is _not_ the order in which the _members_ of the set should be
* initialized. Rather, it represents the order in which the set should be
* initialized in relation to other sets. That is, if
* ```
* getInitializationOrder() = 2
* ```
* then this set will be initialized as the second (third) set in the
* enclosing function. In order words, the third `UninitializedGroup`
* instruction in the entry block of the enclosing function will initialize
* this set of allocations.
*/
final int getInitializationOrder() {
exists(IRFunction func |
func = this.getIRFunction() and
this =
rank[result + 1](VariableGroup vg, string uniq |
vg.getIRFunction() = func and uniq = vg.getUniqueId()
|
vg order by uniq
)
)
}
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
}
private newtype TMemoryLocation =
TVariableMemoryLocation(
Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
IntValue endBitOffset, boolean isMayAccess
) {
(
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
hasResultMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
or
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
hasOperandMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
or
// For a stack variable, always create a memory location for the entire variable.
var.isAlwaysAllocatedOnStack() and
@@ -69,22 +217,14 @@ private newtype TMemoryLocation =
) and
languageType = type.getCanonicalLanguageType()
} or
TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
(
var instanceof IndirectParameterAllocation or
var instanceof DynamicAllocation
) and
(isMayAccess = false or isMayAccess = true)
TEntireAllocationMemoryLocation(Allocation var, Boolean isMayAccess) {
var instanceof IndirectParameterAllocation or
var instanceof DynamicAllocation
} or
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TAllNonLocalMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
} or
TAllAliasedMemory(IRFunction irFunc, boolean isMayAccess) {
isMayAccess = false or isMayAccess = true
}
TGroupedMemoryLocation(VariableGroup vg, Boolean isMayAccess, Boolean isAll) or
TUnknownMemoryLocation(IRFunction irFunc, Boolean isMayAccess) or
TAllNonLocalMemory(IRFunction irFunc, Boolean isMayAccess) or
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
/**
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
@@ -116,7 +256,14 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract predicate isMayAccess();
Allocation getAllocation() { none() }
/**
* Gets an allocation associated with this `MemoryLocation`.
*
* This returns zero or one results in all cases except when `this` is an
* instance of `GroupedMemoryLocation`. When `this` is an instance of
* `GroupedMemoryLocation` this predicate always returns two or more results.
*/
Allocation getAnAllocation() { none() }
/**
* Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for
@@ -153,24 +300,29 @@ abstract class AllocationMemoryLocation extends MemoryLocation {
Allocation var;
boolean isMayAccess;
AllocationMemoryLocation() {
this instanceof TMemoryLocation and
isMayAccess = false
or
isMayAccess = true // Just ensures that `isMayAccess` is bound.
}
bindingset[isMayAccess]
AllocationMemoryLocation() { any() }
final override VirtualVariable getVirtualVariable() {
if allocationEscapes(var)
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
else result.(AllocationMemoryLocation).getAllocation() = var
else (
// It may be that the grouped memory location contains an escaping
// allocation. In that case, the virtual variable is still the memory
// location that represents all aliased memory. Thus, we need to
// call `getVirtualVariable` on the grouped memory location.
result = getGroupedMemoryLocation(var, false, false).getVirtualVariable()
or
not exists(getGroupedMemoryLocation(var, false, false)) and
result.(AllocationMemoryLocation).getAnAllocation() = var
)
}
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
final override Location getLocation() { result = var.getLocation() }
final override Allocation getAllocation() { result = var }
final override Allocation getAnAllocation() { result = var }
final override predicate isMayAccess() { isMayAccess = true }
@@ -211,13 +363,13 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
final override Language::LanguageType getType() {
if
strictcount(Language::LanguageType accessType |
hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _)
hasResultMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false) or
hasOperandMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false)
) = 1
then
// All of the accesses have the same `LanguageType`, so just use that.
hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _) or
hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _)
hasResultMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false) or
hasOperandMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false)
else
// There is no single type for all accesses, so just use the canonical one for this `IRType`.
result = type.getCanonicalLanguageType()
@@ -247,6 +399,89 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
}
}
/**
* A group of allocations represented as a single memory location.
*
* If `isAll()` holds then this memory location represents all the enclosing
* allocations, and if `isSome()` holds then this memory location represents
* one or more of the enclosing allocations.
*
* For example, consider the following snippet:
* ```
* int* p;
* int a, b;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 42;
* ```
*
* The write memory location associated with the write to `*p` writes to a
* grouped memory location representing the _some_ allocation in the set
* `{a, b}`, and the subsequent `Chi` instruction merges the new value of
* `{a, b}` into a memory location that represents _all_ of the allocations
* in the set.
*/
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation {
VariableGroup vg;
boolean isMayAccess;
boolean isAll;
GroupedMemoryLocation() { this = TGroupedMemoryLocation(vg, isMayAccess, isAll) }
final override Location getLocation() { result = vg.getLocation() }
final override IRFunction getIRFunction() { result = vg.getIRFunction() }
final override predicate isMayAccess() { isMayAccess = true }
final override string getUniqueId() {
if this.isAll()
then result = "All{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
else result = "Some{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
}
final override string toStringInternal() { result = this.getUniqueId() }
final override Language::LanguageType getType() { result = vg.getType() }
final override VirtualVariable getVirtualVariable() {
if allocationEscapes(this.getAnAllocation())
then result = TAllAliasedMemory(vg.getIRFunction(), false)
else result = TGroupedMemoryLocation(vg, false, true)
}
/** Gets an allocation of this memory location. */
override Allocation getAnAllocation() { result = vg.getAnAllocation() }
/** Gets the set of allocations associated with this memory location. */
VariableGroup getGroup() { result = vg }
/** Holds if this memory location represents all the enclosing allocations. */
predicate isAll() { isAll = true }
/** Holds if this memory location represents one or more of the enclosing allocations. */
predicate isSome() { isAll = false }
}
private GroupedMemoryLocation getGroupedMemoryLocation(
Allocation alloc, boolean isMayAccess, boolean isAll
) {
result.getAnAllocation() = alloc and
(
isMayAccess = true and result.isMayAccess()
or
isMayAccess = false and not result.isMayAccess()
) and
(
isAll = true and result.isAll()
or
isAll = false and result.isSome()
)
}
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
AllocationMemoryLocation
{
@@ -282,6 +517,14 @@ class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
}
}
class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
GroupedVirtualVariable() {
forex(Allocation var | var = this.getAnAllocation() | not allocationEscapes(var)) and
not this.isMayAccess() and
this.isAll()
}
}
/**
* An access to memory that is not known to be confined to a specific `IRVariable`.
*/
@@ -446,7 +689,7 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
result instanceof MustExactlyOverlap
or
not use instanceof EntireAllocationMemoryLocation and
if def.getAllocation() = use.getAllocation()
if def.getAnAllocation() = use.getAnAllocation()
then
// EntireAllocationMemoryLocation totally overlaps any location within
// the same allocation.
@@ -454,11 +697,48 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
else (
// There is no overlap with a location that's known to belong to a
// different allocation, but all other locations may partially overlap.
not exists(use.getAllocation()) and
not exists(use.getAnAllocation()) and
result instanceof MayPartiallyOverlap
)
)
or
exists(GroupedMemoryLocation group |
group = def and
def.getVirtualVariable() = use.getVirtualVariable()
|
(
use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory
) and
result instanceof MayPartiallyOverlap
or
group.isAll() and
(
group.getAnAllocation() =
[
use.(EntireAllocationMemoryLocation).getAnAllocation(),
use.(VariableMemoryLocation).getAnAllocation()
]
or
use.(GroupedMemoryLocation).isSome()
) and
result instanceof MustTotallyOverlap
or
group.isAll() and
use.(GroupedMemoryLocation).isAll() and
result instanceof MustExactlyOverlap
or
group.isSome() and
(
use instanceof EntireAllocationMemoryLocation
or
use instanceof VariableMemoryLocation
or
use instanceof GroupedMemoryLocation
) and
result instanceof MayPartiallyOverlap
)
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and
(
@@ -468,7 +748,8 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
(
use instanceof UnknownMemoryLocation or
use instanceof AllAliasedMemory or
use instanceof EntireAllocationMemoryLocation
use instanceof EntireAllocationMemoryLocation or
use instanceof GroupedMemoryLocation
) and
result instanceof MayPartiallyOverlap
or
@@ -534,7 +815,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
exists(int startRank, int endRank, VirtualVariable vvar |
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
var = vml.getAllocation() and
var = vml.getAnAllocation() and
vvar = vml.getVirtualVariable() and
isRelatableMemoryLocation(vml) and
offsetRank in [startRank .. endRank]
@@ -542,7 +823,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
}
private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) {
vml.getAllocation() = var and
vml.getAnAllocation() = var and
(
vml.getStartBitOffset() = Ints::unknown() or
vml.getEndBitOffset() = Ints::unknown()
@@ -557,9 +838,9 @@ private predicate overlappingIRVariableMemoryLocations(
isCoveredOffset(var, offsetRank, use)
)
or
hasUnknownOffset(use.getAllocation(), def)
hasUnknownOffset(use.getAnAllocation(), def)
or
hasUnknownOffset(def.getAllocation(), use)
hasUnknownOffset(def.getAnAllocation(), use)
}
private Overlap getVariableMemoryLocationOverlap(
@@ -588,13 +869,24 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
(
(
isIndirectOrBufferMemoryAccess(kind) and
if hasResultMemoryAccess(instr, _, _, _, _, _, _)
if hasResultMemoryAccess(_, instr, _, _, _, _, _, _, _)
then
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
unbindBool(isMayAccess))
exists(
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
boolean grouped
|
hasResultMemoryAccess(_, instr, var, type, _, startBitOffset, endBitOffset, isMayAccess,
grouped)
|
// If the instruction is only associated with one allocation we assign it a `VariableMemoryLocation`
if grouped = false
then
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
unbindBool(isMayAccess))
else
// And otherwise we assign it a memory location that groups all the relevant memory locations into one.
result = getGroupedMemoryLocation(var, unbindBool(isMayAccess), false)
)
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess)
)
@@ -621,12 +913,23 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
(
(
isIndirectOrBufferMemoryAccess(kind) and
if hasOperandMemoryAccess(operand, _, _, _, _, _, _)
if hasOperandMemoryAccess(_, operand, _, _, _, _, _, _, _)
then
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
exists(
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
boolean grouped
|
hasOperandMemoryAccess(_, operand, var, type, _, startBitOffset, endBitOffset,
isMayAccess, grouped)
|
// If the operand is only associated with one memory location we assign it a `VariableMemoryLocation`
if grouped = false
then
result =
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
else
// And otherwise we assign it a memory location that groups all relevant memory locations into one.
result = getGroupedMemoryLocation(var, isMayAccess, false)
)
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
)

View File

@@ -15,6 +15,51 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached
/**
* Holds if `instruction` is the first instruction that may be followed by
* an `UninitializedGroup` instruction, and the enclosing function of
* `instruction` is `func`.
*/
private predicate isFirstInstructionBeforeUninitializedGroup(
Instruction instruction, IRFunction func
) {
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
func = instruction.getEnclosingIRFunction()
}
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
exists(Alias::VariableGroup vg |
vg.getIRFunction() = func and
vg.getInitializationOrder() = i and
result = uninitializedGroup(vg)
)
}
/**
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
* instructions in `func`. The chain of instructions may be empty in which case
* `instruction` satisfies
* ```
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
* ```
*/
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
exists(int i |
instruction = getInitGroupInstruction(i, func) and
not exists(getChi(instruction)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
exists(int i |
instruction = getChi(getInitGroupInstruction(i, func)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
not exists(getInitGroupInstruction(0, func))
}
cached
private module Cached {
cached
@@ -32,6 +77,11 @@ private module Cached {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction |
@@ -45,7 +95,8 @@ private module Cached {
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
TUninitializedGroupInstruction;
/**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -78,6 +129,8 @@ private module Cached {
or
instr instanceof TChiInstruction
or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction
}
@@ -123,7 +176,8 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
}
cached
@@ -134,16 +188,23 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
exists(Instruction input | instruction = getChi(input) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
// variable of the grouped memory location is `{AllAliasedMemory}`.
exists(Alias::GroupedMemoryLocation gml |
input = uninitializedGroup(gml.getGroup()) and
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
)
or
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and
not exists(location.getAllocation())
not exists(location.getAnAllocation())
)
}
@@ -205,7 +266,11 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = getChi(getOldInstruction(result)) and
(
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -263,6 +328,14 @@ private module Cached {
)
}
cached
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
exists(Alias::VariableGroup vg |
init = uninitializedGroup(vg) and
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
@@ -316,6 +389,19 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
}
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
result =
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
int r |
initGroup.getEnclosingIRFunction() = func and
chi = getChi(initGroup) and
initGroup = uninitializedGroup(vg) and
r = vg.getInitializationOrder()
|
chi order by r
)
}
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
@@ -329,6 +415,19 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
)
or
exists(UninitializedGroupInstruction initGroup, IRFunction func |
chiInstr = getChi(initGroup) and
func = initGroup.getEnclosingIRFunction()
|
chiInstr = getChiAfterUninitializedGroup(0, func) and
isFirstInstructionBeforeUninitializedGroup(result, func)
or
exists(int i |
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
result = getChiAfterUninitializedGroup(i, func)
)
)
}
cached
@@ -344,14 +443,40 @@ private module Cached {
)
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
exists(int i, IRFunction func |
func = instruction.getEnclosingIRFunction() and
instruction = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
if hasChiNodeAfterUninitializedGroup(_, instruction)
then result = getChi(instruction)
else result = getInitGroupInstruction(i + 1, func)
)
or
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
func = instruction.getEnclosingIRFunction() and
instruction = getChi(initGroup) and
initGroup = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
result = getInitGroupInstruction(i + 1, func)
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
Instruction instruction, EdgeKind kind
) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = getChi(getOldInstruction(instruction)) and
@@ -371,6 +496,107 @@ private module Cached {
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
isLastInstructionForUninitializedGroups(instruction, func) and
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
)
}
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction.
*
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
* instructions. For example, consider this example:
* ```cpp
* int x, y;
* int* p;
* if(b) {
* p = &x;
* escape(&x);
* } else {
* p = &y;
* }
* *p = 42;
*
* int z, w;
* int* q;
* if(b) {
* q = &z;
* } else {
* q = &w;
* }
* *q = 43;
* ```
*
* the unaliased IR for the entry block of this snippet is:
* ```
* v1(void) = EnterFunction :
* m1(unknown) = AliasedDefinition :
* m2(unknown) = InitializeNonLocal :
* r1(glval<bool>) = VariableAddress[b] :
* m3(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m4(int) = Uninitialized[x] : &:r2
* r3(glval<int>) = VariableAddress[y] :
* m5(int) = Uninitialized[y] : &:r3
* r4(glval<int *>) = VariableAddress[p] :
* m6(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m3
* v2(void) = ConditionalBranch : r6
* ```
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
* instruction for every `VariableGroup` memory location in the function. Furthermore,
* if the `VariableGroup` memory location contains an allocation that escapes we need
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
* `{AllAliasedMemory}`. For the above snippet we then end up with:
* ```
* v1(void) = EnterFunction :
* m2(unknown) = AliasedDefinition :
* m3(unknown) = InitializeNonLocal :
* m4(unknown) = Chi : total:m2, partial:m3
* m5(int) = UninitializedGroup[x,y] :
* m6(unknown) = Chi : total:m4, partial:m5
* m7(int) = UninitializedGroup[w,z] :
* r1(glval<bool>) = VariableAddress[b] :
* m8(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m10(int) = Uninitialized[x] : &:r2
* m11(unknown) = Chi : total:m6, partial:m10
* r3(glval<int>) = VariableAddress[y] :
* m12(int) = Uninitialized[y] : &:r3
* m13(unknown) = Chi : total:m11, partial:m12
* r4(glval<int *>) = VariableAddress[p] :
* m14(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m8
* v2(void) = ConditionalBranch : r6
* ```
*
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
* there is no `Chi` following that the `UninitializedGroup` that initializes the
* memory of `{w, z}`.
*/
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = firstInstructionToUninitializedGroup(instruction, kind)
or
result = getNextUninitializedGroupInstruction(instruction, kind)
or
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
or
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
@@ -406,6 +632,16 @@ private module Cached {
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction().getFunction()
)
or
exists(UninitializedGroupInstruction initGroup |
instr = chiInstruction(initGroup) and
result = getInstructionAst(initGroup)
)
}
cached
@@ -418,9 +654,16 @@ private module Cached {
)
or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
hasChiNode(vvar, primaryInstr)
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
)
or
instr = reusedPhiInstruction(_) and
@@ -448,6 +691,8 @@ private module Cached {
or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
}
@@ -460,10 +705,15 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction()
)
or
exists(OldInstruction primaryInstr |
exists(Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result)
}
@@ -478,6 +728,8 @@ private module Cached {
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
or
instruction = getChi(result.(UninitializedGroupInstruction))
}
}
@@ -485,7 +737,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
@@ -506,6 +758,16 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
)
}
private predicate hasChiNodeAfterUninitializedGroup(
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
) {
exists(Alias::GroupedMemoryLocation defLocation |
initGroup = uninitializedGroup(defLocation.getGroup()) and
defLocation.getVirtualVariable() = vvar and
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
)
}
private import PhiInsertion
/**
@@ -668,19 +930,33 @@ private import DefUse
* potentially very sparse.
*/
module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)
}
bindingset[index, block]
pragma[inline_late]
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
Instruction getDefinitionOrChiInstruction(
private Instruction getDefinitionOrChiInstruction0(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(OldInstruction oldInstr, int oldOffset |
oldInstr = defBlock.getInstruction(oldOffset) and
oldOffset >= 0
|
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
defOffset = getChiOffset(oldOffset, defBlock) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -689,7 +965,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable()
or
// An even offset corresponds to the original instruction.
defOffset = oldOffset * 2 and
defOffset = getNonChiOffset(oldOffset, defBlock) and
result = getNewInstruction(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -702,6 +978,54 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
or
exists(
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
Alias::GroupedMemoryLocation gml
|
// Add 3 to account for the function prologue:
// v1(void) = EnterFunction
// m1(unknown) = AliasedDefinition
// m2(unknown) = InitializeNonLocal
index = 3 + vg.getInitializationOrder() and
not gml.isMayAccess() and
gml.isSome() and
gml.getGroup() = vg and
vg.getIRFunction().getEntryBlock() = defBlock and
initGroup = uninitializedGroup(vg) and
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
result = initGroup and
defOffset = 2 * index and
actualDefLocation = defLocation
or
result = getChi(initGroup) and
defOffset = 2 * index + 1 and
actualDefLocation = defLocation.getVirtualVariable()
)
}
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
isLastInstructionForUninitializedGroups(result, func)
)
}
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(Instruction oldResult |
oldResult =
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
(
result = remapGetDefinitionOrChiInstruction(oldResult)
or
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
result = oldResult
)
)
}
/**
@@ -842,8 +1166,20 @@ module DefUse {
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
)
or
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
index = 3 + vg.getInitializationOrder() and
initGroup = uninitializedGroup(vg) and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = 2 * index // The use will be connected to the definition on the original instruction.
)
}
@@ -904,10 +1240,11 @@ module DefUse {
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
offset = getNonChiOffset(index, block)
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = (index * 2) + 1
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
)
)
}
@@ -1057,5 +1394,9 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
}

View File

@@ -31,6 +31,7 @@ newtype TInstruction =
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
} or
TUnaliasedSsaUninitializedGroupInstruction(UnaliasedSsa::Ssa::VariableGroup vg) or
TAliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
) {
@@ -41,6 +42,12 @@ newtype TInstruction =
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
} or
TAliasedSsaUninitializedGroupInstruction(AliasedSsa::Ssa::VariableGroup vg) or
TAliasedSsaChiAfterUninitializedGroupInstruction(
TAliasedSsaUninitializedGroupInstruction initGroup
) {
AliasedSsa::Ssa::hasChiNodeAfterUninitializedGroup(initGroup)
}
/**
@@ -62,7 +69,11 @@ module UnaliasedSsaInstructions {
class TChiInstruction = TUnaliasedSsaChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
class TUninitializedGroupInstruction = TUnaliasedSsaUninitializedGroupInstruction;
class TRawOrUninitializedGroupInstruction = TRawInstruction or TUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrUninitializedGroupInstruction primaryInstruction) {
result = TUnaliasedSsaChiInstruction(primaryInstruction)
}
@@ -71,6 +82,12 @@ module UnaliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TUnaliasedSsaUnreachedInstruction(irFunc)
}
class VariableGroup = UnaliasedSsa::Ssa::VariableGroup;
// This really should just be `TUnaliasedSsaUninitializedGroupInstruction`, but that makes the
// compiler realize that certain expressions in `SSAConstruction` are unsatisfiable.
TRawOrUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) { none() }
}
/**
@@ -92,10 +109,16 @@ module AliasedSsaInstructions {
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
}
class TChiInstruction = TAliasedSsaChiInstruction;
class TChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
class TRawOrInitialzieGroupInstruction =
TRawInstruction or TAliasedSsaUninitializedGroupInstruction;
TChiInstruction chiInstruction(TRawOrInitialzieGroupInstruction primaryInstruction) {
result = TAliasedSsaChiInstruction(primaryInstruction)
or
result = TAliasedSsaChiAfterUninitializedGroupInstruction(primaryInstruction)
}
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
@@ -103,4 +126,12 @@ module AliasedSsaInstructions {
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSsaUnreachedInstruction(irFunc)
}
class VariableGroup = AliasedSsa::Ssa::VariableGroup;
class TUninitializedGroupInstruction = TAliasedSsaUninitializedGroupInstruction;
TUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) {
result = TAliasedSsaUninitializedGroupInstruction(vg)
}
}

View File

@@ -12,6 +12,9 @@ private import semmle.code.cpp.ir.internal.Overlap
* Provides the newtype used to represent operands across all phases of the IR.
*/
private module Internal {
private class TAliasedChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
/**
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
@@ -52,7 +55,7 @@ private module Internal {
) {
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
} or
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
TAliasedChiOperand(TAliasedChiInstruction useInstr, ChiOperandTag tag) { any() }
}
/**
@@ -198,10 +201,13 @@ module AliasedSsaOperands {
)
}
private class TChiInstruction =
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
/**
* Returns the Chi operand with the specified parameters.
*/
TChiOperand chiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) {
TChiOperand chiOperand(TChiInstruction useInstr, ChiOperandTag tag) {
result = Internal::TAliasedChiOperand(useInstr, tag)
}
}

View File

@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -407,6 +407,8 @@ predicate hasUnreachedInstruction(IRFunction func) {
)
}
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction instr) { none() }
import CachedForDebugging
cached

View File

@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
}
/**
* An instruction that initializes a set of allocations that are each assigned
* the same "virtual variable".
*
* As an example, consider the following snippet:
* ```
* int a;
* int b;
* int* p;
* if(b) {
* p = &a;
* } else {
* p = &b;
* }
* *p = 5;
* int x = a;
* ```
*
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
* analysis will create a region that contains both `a` and `b`. The region
* containing both `a` and `b` are initialized by an `UninitializedGroup`
* instruction in the entry block of the enclosing function.
*/
class UninitializedGroupInstruction extends Instruction {
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
/**
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
* Note: Allocations that are not represented as `IRVariable`s (such as
* dynamic allocations) are not returned by this predicate even if this
* instruction initializes such memory.
*/
final IRVariable getAnIRVariable() {
result = Construction::getAnUninitializedGroupVariable(this)
}
final override string getImmediateString() {
result = strictconcat(this.getAnIRVariable().toString(), ",")
}
}
/**
* An instruction representing unreachable code.
*

View File

@@ -106,8 +106,7 @@ private predicate operandEscapesDomain(Operand operand) {
not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction and
not operand.getUse() instanceof ReturnIndirectionInstruction and
not operand instanceof PhiInputOperand
not operand.getUse() instanceof ReturnIndirectionInstruction
}
/**
@@ -191,6 +190,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
// A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
)
or
operand = instr.(PhiInstruction).getAnInputOperand() and
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
// through the back edge of a loop (or through recursion).
bitOffset = Ints::unknown()
}
private predicate operandEscapesNonReturn(Operand operand) {
@@ -212,9 +216,6 @@ private predicate operandEscapesNonReturn(Operand operand) {
or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
operandEscapesDomain(operand)
}
@@ -236,9 +237,6 @@ private predicate operandMayReachReturn(Operand operand) {
operand.getUse() instanceof ReturnValueInstruction
or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
}
private predicate operandReturned(Operand operand, IntValue bitOffset) {

View File

@@ -15,6 +15,51 @@ private class OldInstruction = Reachability::ReachableInstruction;
import Cached
/**
* Holds if `instruction` is the first instruction that may be followed by
* an `UninitializedGroup` instruction, and the enclosing function of
* `instruction` is `func`.
*/
private predicate isFirstInstructionBeforeUninitializedGroup(
Instruction instruction, IRFunction func
) {
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
func = instruction.getEnclosingIRFunction()
}
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
exists(Alias::VariableGroup vg |
vg.getIRFunction() = func and
vg.getInitializationOrder() = i and
result = uninitializedGroup(vg)
)
}
/**
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
* instructions in `func`. The chain of instructions may be empty in which case
* `instruction` satisfies
* ```
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
* ```
*/
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
exists(int i |
instruction = getInitGroupInstruction(i, func) and
not exists(getChi(instruction)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
exists(int i |
instruction = getChi(getInitGroupInstruction(i, func)) and
not exists(getInitGroupInstruction(i + 1, func))
)
or
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
not exists(getInitGroupInstruction(0, func))
}
cached
private module Cached {
cached
@@ -32,6 +77,11 @@ private module Cached {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
hasChiNodeAfterUninitializedGroup(_, initGroup)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldIR::Instruction oldInstruction |
@@ -45,7 +95,8 @@ private module Cached {
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
TUninitializedGroupInstruction;
/**
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -78,6 +129,8 @@ private module Cached {
or
instr instanceof TChiInstruction
or
instr instanceof TUninitializedGroupInstruction
or
instr instanceof TUnreachedInstruction
}
@@ -123,7 +176,8 @@ private module Cached {
predicate hasModeledMemoryResult(Instruction instruction) {
canModelResultForOldInstruction(getOldInstruction(instruction)) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof ChiInstruction or // Chis always have modeled results
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
}
cached
@@ -134,16 +188,23 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
exists(Instruction input | instruction = getChi(input) |
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
or
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
// variable of the grouped memory location is `{AllAliasedMemory}`.
exists(Alias::GroupedMemoryLocation gml |
input = uninitializedGroup(gml.getGroup()) and
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
)
)
or
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = getPhi(_, location) and
not exists(location.getAllocation())
not exists(location.getAnAllocation())
)
}
@@ -205,7 +266,11 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = getChi(getOldInstruction(result)) and
(
instruction = getChi(getOldInstruction(result))
or
instruction = getChi(result.(UninitializedGroupInstruction))
) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -263,6 +328,14 @@ private module Cached {
)
}
cached
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
exists(Alias::VariableGroup vg |
init = uninitializedGroup(vg) and
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
@@ -316,6 +389,19 @@ private module Cached {
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
}
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
result =
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
int r |
initGroup.getEnclosingIRFunction() = func and
chi = getChi(initGroup) and
initGroup = uninitializedGroup(vg) and
r = vg.getInitializationOrder()
|
chi order by r
)
}
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
@@ -329,6 +415,19 @@ private module Cached {
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
)
or
exists(UninitializedGroupInstruction initGroup, IRFunction func |
chiInstr = getChi(initGroup) and
func = initGroup.getEnclosingIRFunction()
|
chiInstr = getChiAfterUninitializedGroup(0, func) and
isFirstInstructionBeforeUninitializedGroup(result, func)
or
exists(int i |
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
result = getChiAfterUninitializedGroup(i, func)
)
)
}
cached
@@ -344,14 +443,40 @@ private module Cached {
)
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
result = getInitGroupInstruction(0, func) and
kind instanceof GotoEdge
)
}
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
exists(int i, IRFunction func |
func = instruction.getEnclosingIRFunction() and
instruction = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
if hasChiNodeAfterUninitializedGroup(_, instruction)
then result = getChi(instruction)
else result = getInitGroupInstruction(i + 1, func)
)
or
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
func = instruction.getEnclosingIRFunction() and
instruction = getChi(initGroup) and
initGroup = getInitGroupInstruction(i, func) and
kind instanceof GotoEdge
|
result = getInitGroupInstruction(i + 1, func)
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
Instruction instruction, EdgeKind kind
) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = getChi(getOldInstruction(instruction)) and
@@ -371,6 +496,107 @@ private module Cached {
)
}
private Instruction getInstructionSuccessorAfterUninitializedGroup(
Instruction instruction, EdgeKind kind
) {
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
isLastInstructionForUninitializedGroups(instruction, func) and
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
)
}
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction.
*
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
* instructions. For example, consider this example:
* ```cpp
* int x, y;
* int* p;
* if(b) {
* p = &x;
* escape(&x);
* } else {
* p = &y;
* }
* *p = 42;
*
* int z, w;
* int* q;
* if(b) {
* q = &z;
* } else {
* q = &w;
* }
* *q = 43;
* ```
*
* the unaliased IR for the entry block of this snippet is:
* ```
* v1(void) = EnterFunction :
* m1(unknown) = AliasedDefinition :
* m2(unknown) = InitializeNonLocal :
* r1(glval<bool>) = VariableAddress[b] :
* m3(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m4(int) = Uninitialized[x] : &:r2
* r3(glval<int>) = VariableAddress[y] :
* m5(int) = Uninitialized[y] : &:r3
* r4(glval<int *>) = VariableAddress[p] :
* m6(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m3
* v2(void) = ConditionalBranch : r6
* ```
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
* instruction for every `VariableGroup` memory location in the function. Furthermore,
* if the `VariableGroup` memory location contains an allocation that escapes we need
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
* `{AllAliasedMemory}`. For the above snippet we then end up with:
* ```
* v1(void) = EnterFunction :
* m2(unknown) = AliasedDefinition :
* m3(unknown) = InitializeNonLocal :
* m4(unknown) = Chi : total:m2, partial:m3
* m5(int) = UninitializedGroup[x,y] :
* m6(unknown) = Chi : total:m4, partial:m5
* m7(int) = UninitializedGroup[w,z] :
* r1(glval<bool>) = VariableAddress[b] :
* m8(bool) = InitializeParameter[b] : &:r1
* r2(glval<int>) = VariableAddress[x] :
* m10(int) = Uninitialized[x] : &:r2
* m11(unknown) = Chi : total:m6, partial:m10
* r3(glval<int>) = VariableAddress[y] :
* m12(int) = Uninitialized[y] : &:r3
* m13(unknown) = Chi : total:m11, partial:m12
* r4(glval<int *>) = VariableAddress[p] :
* m14(int *) = Uninitialized[p] : &:r4
* r5(glval<bool>) = VariableAddress[b] :
* r6(bool) = Load[b] : &:r5, m8
* v2(void) = ConditionalBranch : r6
* ```
*
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
* there is no `Chi` following that the `UninitializedGroup` that initializes the
* memory of `{w, z}`.
*/
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = firstInstructionToUninitializedGroup(instruction, kind)
or
result = getNextUninitializedGroupInstruction(instruction, kind)
or
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
or
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
@@ -406,6 +632,16 @@ private module Cached {
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction().getFunction()
)
or
exists(UninitializedGroupInstruction initGroup |
instr = chiInstruction(initGroup) and
result = getInstructionAst(initGroup)
)
}
cached
@@ -418,9 +654,16 @@ private module Cached {
)
or
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
hasChiNode(vvar, primaryInstr)
or
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getType()
)
or
instr = reusedPhiInstruction(_) and
@@ -448,6 +691,8 @@ private module Cached {
or
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
or
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
or
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
}
@@ -460,10 +705,15 @@ private module Cached {
result = blockStartInstr.getEnclosingIRFunction()
)
or
exists(OldInstruction primaryInstr |
exists(Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
exists(Alias::VariableGroup vg |
instr = uninitializedGroup(vg) and
result = vg.getIRFunction()
)
or
instr = unreachedInstruction(result)
}
@@ -478,6 +728,8 @@ private module Cached {
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
or
instruction = getChi(result.(UninitializedGroupInstruction))
}
}
@@ -485,7 +737,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
@@ -506,6 +758,16 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
)
}
private predicate hasChiNodeAfterUninitializedGroup(
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
) {
exists(Alias::GroupedMemoryLocation defLocation |
initGroup = uninitializedGroup(defLocation.getGroup()) and
defLocation.getVirtualVariable() = vvar and
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
)
}
private import PhiInsertion
/**
@@ -668,19 +930,33 @@ private import DefUse
* potentially very sparse.
*/
module DefUse {
bindingset[index, block]
pragma[inline_late]
private int getNonChiOffset(int index, OldBlock block) {
exists(IRFunction func | func = block.getEnclosingIRFunction() |
if
getNewBlock(block) = func.getEntryBlock() and
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
else result = 2 * index
)
}
bindingset[index, block]
pragma[inline_late]
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
Instruction getDefinitionOrChiInstruction(
private Instruction getDefinitionOrChiInstruction0(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(OldInstruction oldInstr, int oldOffset |
oldInstr = defBlock.getInstruction(oldOffset) and
oldOffset >= 0
|
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
defOffset = getChiOffset(oldOffset, defBlock) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -689,7 +965,7 @@ module DefUse {
actualDefLocation = defLocation.getVirtualVariable()
or
// An even offset corresponds to the original instruction.
defOffset = oldOffset * 2 and
defOffset = getNonChiOffset(oldOffset, defBlock) and
result = getNewInstruction(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
@@ -702,6 +978,54 @@ module DefUse {
hasDefinition(_, defLocation, defBlock, defOffset) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
or
exists(
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
Alias::GroupedMemoryLocation gml
|
// Add 3 to account for the function prologue:
// v1(void) = EnterFunction
// m1(unknown) = AliasedDefinition
// m2(unknown) = InitializeNonLocal
index = 3 + vg.getInitializationOrder() and
not gml.isMayAccess() and
gml.isSome() and
gml.getGroup() = vg and
vg.getIRFunction().getEntryBlock() = defBlock and
initGroup = uninitializedGroup(vg) and
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
result = initGroup and
defOffset = 2 * index and
actualDefLocation = defLocation
or
result = getChi(initGroup) and
defOffset = 2 * index + 1 and
actualDefLocation = defLocation.getVirtualVariable()
)
}
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
exists(IRFunction func |
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
isLastInstructionForUninitializedGroups(result, func)
)
}
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
Alias::MemoryLocation actualDefLocation
) {
exists(Instruction oldResult |
oldResult =
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
(
result = remapGetDefinitionOrChiInstruction(oldResult)
or
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
result = oldResult
)
)
}
/**
@@ -842,8 +1166,20 @@ module DefUse {
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
)
or
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
index = 3 + vg.getInitializationOrder() and
initGroup = uninitializedGroup(vg) and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = 2 * index // The use will be connected to the definition on the original instruction.
)
}
@@ -904,10 +1240,11 @@ module DefUse {
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
offset = getNonChiOffset(index, block)
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = (index * 2) + 1
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
)
)
}
@@ -1057,5 +1394,9 @@ module Ssa {
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
class VariableGroup = Alias::VariableGroup;
}

View File

@@ -2,6 +2,7 @@ import AliasAnalysis
private import SimpleSSAImports
import SimpleSSAPublicImports
private import AliasConfiguration
private import codeql.util.Unit
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
exists(Instruction constantBase, int bitOffset |
@@ -48,7 +49,7 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
private MemoryLocation getMemoryLocation(Allocation var) { result.getAnAllocation() = var }
class MemoryLocation extends TMemoryLocation {
Allocation var;
@@ -57,7 +58,7 @@ class MemoryLocation extends TMemoryLocation {
final string toString() { result = var.getAllocationString() }
final Allocation getAllocation() { result = var }
final Allocation getAnAllocation() { result = var }
final Language::Location getLocation() { result = var.getLocation() }
@@ -77,6 +78,40 @@ class MemoryLocation extends TMemoryLocation {
predicate canReuseSsaForOldResult(Instruction instr) { none() }
abstract class VariableGroup extends Unit {
abstract Allocation getAnAllocation();
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
abstract Language::Location getLocation();
abstract IRFunction getIRFunction();
abstract Language::LanguageType getType();
abstract int getInitializationOrder();
}
class GroupedMemoryLocation extends MemoryLocation {
VariableGroup vg;
GroupedMemoryLocation() { none() }
/** Gets an allocation of this memory location. */
Allocation getAnAllocation() { result = vg.getAnAllocation() }
/** Gets the set of allocations associated with this memory location. */
VariableGroup getGroup() { result = vg }
predicate isMayAccess() { none() }
/** Holds if this memory location represents all the enclosing allocations. */
predicate isAll() { none() }
/** Holds if this memory location represents one or more of the enclosing allocations. */
predicate isSome() { none() }
}
/**
* Represents a set of `MemoryLocation`s that cannot overlap with
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be

View File

@@ -22649,6 +22649,616 @@ ir.cpp:
# 2556| Type = [LongType] unsigned long
# 2556| ValueCategory = prvalue(load)
# 2557| getStmt(1): [ReturnStmt] return ...
# 2559| [TopLevelFunction] void p_points_to_x_or_y(int, int)
# 2559| <params>:
# 2559| getParameter(0): [Parameter] a
# 2559| Type = [IntType] int
# 2559| getParameter(1): [Parameter] b
# 2559| Type = [IntType] int
# 2559| getEntryPoint(): [BlockStmt] { ... }
# 2560| getStmt(0): [DeclStmt] declaration
# 2560| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2560| Type = [IntType] int
# 2561| getStmt(1): [DeclStmt] declaration
# 2561| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2561| Type = [IntType] int
# 2562| getStmt(2): [DeclStmt] declaration
# 2562| getDeclarationEntry(0): [VariableDeclarationEntry] definition of p
# 2562| Type = [IntPointerType] int *
# 2563| getStmt(3): [IfStmt] if (...) ...
# 2563| getCondition(): [LTExpr] ... < ...
# 2563| Type = [BoolType] bool
# 2563| ValueCategory = prvalue
# 2563| getLesserOperand(): [VariableAccess] a
# 2563| Type = [IntType] int
# 2563| ValueCategory = prvalue(load)
# 2563| getGreaterOperand(): [VariableAccess] b
# 2563| Type = [IntType] int
# 2563| ValueCategory = prvalue(load)
# 2563| getThen(): [BlockStmt] { ... }
# 2564| getStmt(0): [ExprStmt] ExprStmt
# 2564| getExpr(): [AssignExpr] ... = ...
# 2564| Type = [IntPointerType] int *
# 2564| ValueCategory = lvalue
# 2564| getLValue(): [VariableAccess] p
# 2564| Type = [IntPointerType] int *
# 2564| ValueCategory = lvalue
# 2564| getRValue(): [AddressOfExpr] & ...
# 2564| Type = [IntPointerType] int *
# 2564| ValueCategory = prvalue
# 2564| getOperand(): [VariableAccess] x
# 2564| Type = [IntType] int
# 2564| ValueCategory = lvalue
# 2565| getElse(): [BlockStmt] { ... }
# 2566| getStmt(0): [ExprStmt] ExprStmt
# 2566| getExpr(): [AssignExpr] ... = ...
# 2566| Type = [IntPointerType] int *
# 2566| ValueCategory = lvalue
# 2566| getLValue(): [VariableAccess] p
# 2566| Type = [IntPointerType] int *
# 2566| ValueCategory = lvalue
# 2566| getRValue(): [AddressOfExpr] & ...
# 2566| Type = [IntPointerType] int *
# 2566| ValueCategory = prvalue
# 2566| getOperand(): [VariableAccess] y
# 2566| Type = [IntType] int
# 2566| ValueCategory = lvalue
# 2568| getStmt(4): [ExprStmt] ExprStmt
# 2568| getExpr(): [AssignExpr] ... = ...
# 2568| Type = [IntType] int
# 2568| ValueCategory = lvalue
# 2568| getLValue(): [PointerDereferenceExpr] * ...
# 2568| Type = [IntType] int
# 2568| ValueCategory = lvalue
# 2568| getOperand(): [VariableAccess] p
# 2568| Type = [IntPointerType] int *
# 2568| ValueCategory = prvalue(load)
# 2568| getRValue(): [Literal] 5
# 2568| Type = [IntType] int
# 2568| Value = [Literal] 5
# 2568| ValueCategory = prvalue
# 2569| getStmt(5): [DeclStmt] declaration
# 2569| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z
# 2569| Type = [IntType] int
# 2569| getVariable().getInitializer(): [Initializer] initializer for z
# 2569| getExpr(): [VariableAccess] x
# 2569| Type = [IntType] int
# 2569| ValueCategory = prvalue(load)
# 2570| getStmt(6): [DeclStmt] declaration
# 2570| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w
# 2570| Type = [IntType] int
# 2570| getVariable().getInitializer(): [Initializer] initializer for w
# 2570| getExpr(): [VariableAccess] y
# 2570| Type = [IntType] int
# 2570| ValueCategory = prvalue(load)
# 2571| getStmt(7): [ReturnStmt] return ...
# 2573| [TopLevelFunction] int phi_after_while()
# 2573| <params>:
# 2573| getEntryPoint(): [BlockStmt] { ... }
# 2574| getStmt(0): [DeclStmt] declaration
# 2574| getDeclarationEntry(0): [VariableDeclarationEntry] definition of r
# 2574| Type = [IntType] int
# 2575| getStmt(1): [DeclStmt] declaration
# 2575| getDeclarationEntry(0): [VariableDeclarationEntry] definition of rP
# 2575| Type = [IntPointerType] int *
# 2575| getVariable().getInitializer(): [Initializer] initializer for rP
# 2575| getExpr(): [AddressOfExpr] & ...
# 2575| Type = [IntPointerType] int *
# 2575| ValueCategory = prvalue
# 2575| getOperand(): [VariableAccess] r
# 2575| Type = [IntType] int
# 2575| ValueCategory = lvalue
# 2577| getStmt(2): [WhileStmt] while (...) ...
# 2577| getCondition(): [FunctionCall] call to predicateA
# 2577| Type = [BoolType] bool
# 2577| ValueCategory = prvalue
# 2577| getStmt(): [BlockStmt] { ... }
# 2578| getStmt(0): [DeclStmt] declaration
# 2578| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
# 2578| Type = [IntType] int
# 2578| getVariable().getInitializer(): [Initializer] initializer for s
# 2578| getExpr(): [Literal] 0
# 2578| Type = [IntType] int
# 2578| Value = [Literal] 0
# 2578| ValueCategory = prvalue
# 2579| getStmt(1): [ExprStmt] ExprStmt
# 2579| getExpr(): [AssignExpr] ... = ...
# 2579| Type = [IntType] int
# 2579| ValueCategory = lvalue
# 2579| getLValue(): [PointerDereferenceExpr] * ...
# 2579| Type = [IntType] int
# 2579| ValueCategory = lvalue
# 2579| getOperand(): [VariableAccess] rP
# 2579| Type = [IntPointerType] int *
# 2579| ValueCategory = prvalue(load)
# 2579| getRValue(): [VariableAccess] s
# 2579| Type = [IntType] int
# 2579| ValueCategory = prvalue(load)
# 2580| getStmt(2): [ExprStmt] ExprStmt
# 2580| getExpr(): [AssignExpr] ... = ...
# 2580| Type = [IntPointerType] int *
# 2580| ValueCategory = lvalue
# 2580| getLValue(): [VariableAccess] rP
# 2580| Type = [IntPointerType] int *
# 2580| ValueCategory = lvalue
# 2580| getRValue(): [AddressOfExpr] & ...
# 2580| Type = [IntPointerType] int *
# 2580| ValueCategory = prvalue
# 2580| getOperand(): [VariableAccess] s
# 2580| Type = [IntType] int
# 2580| ValueCategory = lvalue
# 2583| getStmt(3): [ReturnStmt] return ...
# 2583| getExpr(): [VariableAccess] r
# 2583| Type = [IntType] int
# 2583| ValueCategory = prvalue(load)
# 2588| [TopLevelFunction] char* recursive_conditional_call_with_increment(char*, bool)
# 2588| <params>:
# 2588| getParameter(0): [Parameter] d
# 2588| Type = [CharPointerType] char *
# 2588| getParameter(1): [Parameter] b
# 2588| Type = [BoolType] bool
# 2589| getEntryPoint(): [BlockStmt] { ... }
# 2590| getStmt(0): [IfStmt] if (...) ...
# 2590| getCondition(): [VariableAccess] b
# 2590| Type = [BoolType] bool
# 2590| ValueCategory = prvalue(load)
# 2590| getThen(): [BlockStmt] { ... }
# 2591| getStmt(0): [ExprStmt] ExprStmt
# 2591| getExpr(): [AssignExpr] ... = ...
# 2591| Type = [CharPointerType] char *
# 2591| ValueCategory = lvalue
# 2591| getLValue(): [VariableAccess] d
# 2591| Type = [CharPointerType] char *
# 2591| ValueCategory = lvalue
# 2591| getRValue(): [FunctionCall] call to recursive_conditional_call_with_increment
# 2591| Type = [CharPointerType] char *
# 2591| ValueCategory = prvalue
# 2591| getArgument(0): [VariableAccess] d
# 2591| Type = [CharPointerType] char *
# 2591| ValueCategory = prvalue(load)
# 2591| getArgument(1): [VariableAccess] b
# 2591| Type = [BoolType] bool
# 2591| ValueCategory = prvalue(load)
# 2593| getStmt(1): [ExprStmt] ExprStmt
# 2593| getExpr(): [PostfixIncrExpr] ... ++
# 2593| Type = [CharPointerType] char *
# 2593| ValueCategory = prvalue
# 2593| getOperand(): [VariableAccess] d
# 2593| Type = [CharPointerType] char *
# 2593| ValueCategory = lvalue
# 2594| getStmt(2): [ReturnStmt] return ...
# 2594| getExpr(): [VariableAccess] d
# 2594| Type = [CharPointerType] char *
# 2594| ValueCategory = prvalue(load)
# 2597| [CopyAssignmentOperator] Recursive& Recursive::operator=(Recursive const&)
# 2597| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const Recursive &
# 2597| [MoveAssignmentOperator] Recursive& Recursive::operator=(Recursive&&)
# 2597| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] Recursive &&
# 2602| [TopLevelFunction] Recursive* merge(Recursive*)
# 2602| <params>:
# 2602| getParameter(0): [Parameter] a
# 2602| Type = [PointerType] Recursive *
# 2603| getEntryPoint(): [BlockStmt] { ... }
# 2604| getStmt(0): [DeclStmt] declaration
# 2604| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
# 2604| Type = [PointerType] Recursive *
# 2605| getStmt(1): [DeclStmt] declaration
# 2605| getDeclarationEntry(0): [VariableDeclarationEntry] definition of p
# 2605| Type = [PointerType] Recursive **
# 2605| getVariable().getInitializer(): [Initializer] initializer for p
# 2605| getExpr(): [AddressOfExpr] & ...
# 2605| Type = [PointerType] Recursive **
# 2605| ValueCategory = prvalue
# 2605| getOperand(): [VariableAccess] b
# 2605| Type = [PointerType] Recursive *
# 2605| ValueCategory = lvalue
# 2607| getStmt(2): [WhileStmt] while (...) ...
# 2607| getCondition(): [FunctionCall] call to predicateA
# 2607| Type = [BoolType] bool
# 2607| ValueCategory = prvalue
# 2608| getStmt(): [BlockStmt] { ... }
# 2609| getStmt(0): [ExprStmt] ExprStmt
# 2609| getExpr(): [AssignExpr] ... = ...
# 2609| Type = [PointerType] Recursive *
# 2609| ValueCategory = lvalue
# 2609| getLValue(): [PointerDereferenceExpr] * ...
# 2609| Type = [PointerType] Recursive *
# 2609| ValueCategory = lvalue
# 2609| getOperand(): [VariableAccess] p
# 2609| Type = [PointerType] Recursive **
# 2609| ValueCategory = prvalue(load)
# 2609| getRValue(): [VariableAccess] a
# 2609| Type = [PointerType] Recursive *
# 2609| ValueCategory = prvalue(load)
# 2610| getStmt(1): [ExprStmt] ExprStmt
# 2610| getExpr(): [AssignExpr] ... = ...
# 2610| Type = [PointerType] Recursive **
# 2610| ValueCategory = lvalue
# 2610| getLValue(): [VariableAccess] p
# 2610| Type = [PointerType] Recursive **
# 2610| ValueCategory = lvalue
# 2610| getRValue(): [AddressOfExpr] & ...
# 2610| Type = [PointerType] Recursive **
# 2610| ValueCategory = prvalue
# 2610| getOperand(): [PointerFieldAccess] next
# 2610| Type = [PointerType] Recursive *
# 2610| ValueCategory = lvalue
# 2610| getQualifier(): [VariableAccess] a
# 2610| Type = [PointerType] Recursive *
# 2610| ValueCategory = prvalue(load)
# 2613| getStmt(3): [ReturnStmt] return ...
# 2613| getExpr(): [VariableAccess] b
# 2613| Type = [PointerType] Recursive *
# 2613| ValueCategory = prvalue(load)
# 2616| [TopLevelFunction] void use_const_int(int const*)
# 2616| <params>:
# 2616| getParameter(0): [Parameter] (unnamed parameter 0)
# 2616| Type = [PointerType] const int *
# 2618| [TopLevelFunction] void escaping_pointer(bool)
# 2618| <params>:
# 2618| getParameter(0): [Parameter] b
# 2618| Type = [BoolType] bool
# 2619| getEntryPoint(): [BlockStmt] { ... }
# 2620| getStmt(0): [DeclStmt] declaration
# 2620| getDeclarationEntry(0): [VariableDeclarationEntry] definition of data
# 2620| Type = [IntPointerType] int *
# 2621| getStmt(1): [DeclStmt] declaration
# 2621| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l1
# 2621| Type = [IntType] int
# 2621| getDeclarationEntry(1): [VariableDeclarationEntry] definition of l2
# 2621| Type = [IntType] int
# 2622| getStmt(2): [IfStmt] if (...) ...
# 2622| getCondition(): [VariableAccess] b
# 2622| Type = [BoolType] bool
# 2622| ValueCategory = prvalue(load)
# 2623| getThen(): [BlockStmt] { ... }
# 2624| getStmt(0): [ExprStmt] ExprStmt
# 2624| getExpr(): [AssignExpr] ... = ...
# 2624| Type = [IntPointerType] int *
# 2624| ValueCategory = lvalue
# 2624| getLValue(): [VariableAccess] data
# 2624| Type = [IntPointerType] int *
# 2624| ValueCategory = lvalue
# 2624| getRValue(): [AddressOfExpr] & ...
# 2624| Type = [IntPointerType] int *
# 2624| ValueCategory = prvalue
# 2624| getOperand(): [VariableAccess] l1
# 2624| Type = [IntType] int
# 2624| ValueCategory = lvalue
# 2627| getElse(): [BlockStmt] { ... }
# 2628| getStmt(0): [ExprStmt] ExprStmt
# 2628| getExpr(): [AssignExpr] ... = ...
# 2628| Type = [IntPointerType] int *
# 2628| ValueCategory = lvalue
# 2628| getLValue(): [VariableAccess] data
# 2628| Type = [IntPointerType] int *
# 2628| ValueCategory = lvalue
# 2628| getRValue(): [AddressOfExpr] & ...
# 2628| Type = [IntPointerType] int *
# 2628| ValueCategory = prvalue
# 2628| getOperand(): [VariableAccess] l2
# 2628| Type = [IntType] int
# 2628| ValueCategory = lvalue
# 2630| getStmt(3): [ExprStmt] ExprStmt
# 2630| getExpr(): [FunctionCall] call to use_const_int
# 2630| Type = [VoidType] void
# 2630| ValueCategory = prvalue
# 2630| getArgument(0): [VariableAccess] data
# 2630| Type = [IntPointerType] int *
# 2630| ValueCategory = prvalue(load)
# 2630| getArgument(0).getFullyConverted(): [CStyleCast] (const int *)...
# 2630| Conversion = [PointerConversion] pointer conversion
# 2630| Type = [PointerType] const int *
# 2630| ValueCategory = prvalue
# 2631| getStmt(4): [ReturnStmt] return ...
# 2636| [TopLevelFunction] void* malloc(unsigned long)
# 2636| <params>:
# 2636| getParameter(0): [Parameter] (unnamed parameter 0)
# 2636| Type = [LongType] unsigned long
# 2637| [TopLevelFunction] void use_const_void_pointer(void const*)
# 2637| <params>:
# 2637| getParameter(0): [Parameter] (unnamed parameter 0)
# 2637| Type = [PointerType] const void *
# 2639| [TopLevelFunction] void needs_chi_for_initialize_groups()
# 2639| <params>:
# 2640| getEntryPoint(): [BlockStmt] { ... }
# 2641| getStmt(0): [IfStmt] if (...) ...
# 2641| getCondition(): [FunctionCall] call to predicateA
# 2641| Type = [BoolType] bool
# 2641| ValueCategory = prvalue
# 2642| getThen(): [BlockStmt] { ... }
# 2643| getStmt(0): [DeclStmt] declaration
# 2643| getDeclarationEntry(0): [VariableDeclarationEntry] definition of data
# 2643| Type = [PointerType] int64_t *
# 2643| getVariable().getInitializer(): [Initializer] initializer for data
# 2643| getExpr(): [FunctionCall] call to malloc
# 2643| Type = [VoidPointerType] void *
# 2643| ValueCategory = prvalue
# 2643| getArgument(0): [Literal] 100
# 2643| Type = [IntType] int
# 2643| Value = [Literal] 100
# 2643| ValueCategory = prvalue
# 2643| getArgument(0).getFullyConverted(): [CStyleCast] (unsigned long)...
# 2643| Conversion = [IntegralConversion] integral conversion
# 2643| Type = [LongType] unsigned long
# 2643| Value = [CStyleCast] 100
# 2643| ValueCategory = prvalue
# 2643| getExpr().getFullyConverted(): [CStyleCast] (int64_t *)...
# 2643| Conversion = [PointerConversion] pointer conversion
# 2643| Type = [PointerType] int64_t *
# 2643| ValueCategory = prvalue
# 2644| getStmt(1): [IfStmt] if (...) ...
# 2644| getCondition(): [NEExpr] ... != ...
# 2644| Type = [BoolType] bool
# 2644| ValueCategory = prvalue
# 2644| getLeftOperand(): [VariableAccess] data
# 2644| Type = [PointerType] int64_t *
# 2644| ValueCategory = prvalue(load)
# 2644| getRightOperand(): [Literal] 0
# 2644| Type = [IntType] int
# 2644| Value = [Literal] 0
# 2644| ValueCategory = prvalue
# 2644| getLeftOperand().getFullyConverted(): [CStyleCast] (void *)...
# 2644| Conversion = [PointerConversion] pointer conversion
# 2644| Type = [VoidPointerType] void *
# 2644| ValueCategory = prvalue
# 2644| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
# 2644| Type = [VoidPointerType] void *
# 2644| Value = [ParenthesisExpr] 0
# 2644| ValueCategory = prvalue
# 2644| getExpr(): [CStyleCast] (void *)...
# 2644| Conversion = [IntegralToPointerConversion] integral to pointer conversion
# 2644| Type = [VoidPointerType] void *
# 2644| Value = [CStyleCast] 0
# 2644| ValueCategory = prvalue
# 2645| getThen(): [BlockStmt] { ... }
# 2646| getStmt(0): [ExprStmt] ExprStmt
# 2646| getExpr(): [AssignExpr] ... = ...
# 2646| Type = [PointerType] int64_t *
# 2646| ValueCategory = lvalue
# 2646| getLValue(): [VariableAccess] data
# 2646| Type = [PointerType] int64_t *
# 2646| ValueCategory = lvalue
# 2646| getRValue(): [FunctionCall] call to malloc
# 2646| Type = [VoidPointerType] void *
# 2646| ValueCategory = prvalue
# 2646| getArgument(0): [Literal] 100
# 2646| Type = [IntType] int
# 2646| Value = [Literal] 100
# 2646| ValueCategory = prvalue
# 2646| getArgument(0).getFullyConverted(): [CStyleCast] (unsigned long)...
# 2646| Conversion = [IntegralConversion] integral conversion
# 2646| Type = [LongType] unsigned long
# 2646| Value = [CStyleCast] 100
# 2646| ValueCategory = prvalue
# 2646| getRValue().getFullyConverted(): [CStyleCast] (int64_t *)...
# 2646| Conversion = [PointerConversion] pointer conversion
# 2646| Type = [PointerType] int64_t *
# 2646| ValueCategory = prvalue
# 2648| getStmt(2): [ExprStmt] ExprStmt
# 2648| getExpr(): [FunctionCall] call to use_const_void_pointer
# 2648| Type = [VoidType] void
# 2648| ValueCategory = prvalue
# 2648| getArgument(0): [VariableAccess] data
# 2648| Type = [PointerType] int64_t *
# 2648| ValueCategory = prvalue(load)
# 2648| getArgument(0).getFullyConverted(): [CStyleCast] (const void *)...
# 2648| Conversion = [PointerConversion] pointer conversion
# 2648| Type = [PointerType] const void *
# 2648| ValueCategory = prvalue
# 2651| getElse(): [BlockStmt] { ... }
# 2652| getStmt(0): [DeclStmt] declaration
# 2652| getDeclarationEntry(0): [VariableDeclarationEntry] definition of data
# 2652| Type = [PointerType] int64_t *
# 2652| getVariable().getInitializer(): [Initializer] initializer for data
# 2652| getExpr(): [FunctionCall] call to malloc
# 2652| Type = [VoidPointerType] void *
# 2652| ValueCategory = prvalue
# 2652| getArgument(0): [Literal] 100
# 2652| Type = [IntType] int
# 2652| Value = [Literal] 100
# 2652| ValueCategory = prvalue
# 2652| getArgument(0).getFullyConverted(): [CStyleCast] (unsigned long)...
# 2652| Conversion = [IntegralConversion] integral conversion
# 2652| Type = [LongType] unsigned long
# 2652| Value = [CStyleCast] 100
# 2652| ValueCategory = prvalue
# 2652| getExpr().getFullyConverted(): [CStyleCast] (int64_t *)...
# 2652| Conversion = [PointerConversion] pointer conversion
# 2652| Type = [PointerType] int64_t *
# 2652| ValueCategory = prvalue
# 2653| getStmt(1): [IfStmt] if (...) ...
# 2653| getCondition(): [NEExpr] ... != ...
# 2653| Type = [BoolType] bool
# 2653| ValueCategory = prvalue
# 2653| getLeftOperand(): [VariableAccess] data
# 2653| Type = [PointerType] int64_t *
# 2653| ValueCategory = prvalue(load)
# 2653| getRightOperand(): [Literal] 0
# 2653| Type = [IntType] int
# 2653| Value = [Literal] 0
# 2653| ValueCategory = prvalue
# 2653| getLeftOperand().getFullyConverted(): [CStyleCast] (void *)...
# 2653| Conversion = [PointerConversion] pointer conversion
# 2653| Type = [VoidPointerType] void *
# 2653| ValueCategory = prvalue
# 2653| getRightOperand().getFullyConverted(): [ParenthesisExpr] (...)
# 2653| Type = [VoidPointerType] void *
# 2653| Value = [ParenthesisExpr] 0
# 2653| ValueCategory = prvalue
# 2653| getExpr(): [CStyleCast] (void *)...
# 2653| Conversion = [IntegralToPointerConversion] integral to pointer conversion
# 2653| Type = [VoidPointerType] void *
# 2653| Value = [CStyleCast] 0
# 2653| ValueCategory = prvalue
# 2654| getThen(): [BlockStmt] { ... }
# 2655| getStmt(0): [ExprStmt] ExprStmt
# 2655| getExpr(): [AssignExpr] ... = ...
# 2655| Type = [PointerType] int64_t *
# 2655| ValueCategory = lvalue
# 2655| getLValue(): [VariableAccess] data
# 2655| Type = [PointerType] int64_t *
# 2655| ValueCategory = lvalue
# 2655| getRValue(): [FunctionCall] call to malloc
# 2655| Type = [VoidPointerType] void *
# 2655| ValueCategory = prvalue
# 2655| getArgument(0): [Literal] 200
# 2655| Type = [IntType] int
# 2655| Value = [Literal] 200
# 2655| ValueCategory = prvalue
# 2655| getArgument(0).getFullyConverted(): [CStyleCast] (unsigned long)...
# 2655| Conversion = [IntegralConversion] integral conversion
# 2655| Type = [LongType] unsigned long
# 2655| Value = [CStyleCast] 200
# 2655| ValueCategory = prvalue
# 2655| getRValue().getFullyConverted(): [CStyleCast] (int64_t *)...
# 2655| Conversion = [PointerConversion] pointer conversion
# 2655| Type = [PointerType] int64_t *
# 2655| ValueCategory = prvalue
# 2657| getStmt(2): [ExprStmt] ExprStmt
# 2657| getExpr(): [FunctionCall] call to use_const_void_pointer
# 2657| Type = [VoidType] void
# 2657| ValueCategory = prvalue
# 2657| getArgument(0): [VariableAccess] data
# 2657| Type = [PointerType] int64_t *
# 2657| ValueCategory = prvalue(load)
# 2657| getArgument(0).getFullyConverted(): [CStyleCast] (const void *)...
# 2657| Conversion = [PointerConversion] pointer conversion
# 2657| Type = [PointerType] const void *
# 2657| ValueCategory = prvalue
# 2659| getStmt(1): [ReturnStmt] return ...
# 2661| [TopLevelFunction] void use_int(int)
# 2661| <params>:
# 2661| getParameter(0): [Parameter] (unnamed parameter 0)
# 2661| Type = [IntType] int
# 2663| [TopLevelFunction] void phi_with_single_input_at_merge(bool)
# 2663| <params>:
# 2663| getParameter(0): [Parameter] b
# 2663| Type = [BoolType] bool
# 2664| getEntryPoint(): [BlockStmt] { ... }
# 2665| getStmt(0): [DeclStmt] declaration
# 2665| getDeclarationEntry(0): [VariableDeclarationEntry] definition of data
# 2665| Type = [IntPointerType] int *
# 2665| getVariable().getInitializer(): [Initializer] initializer for data
# 2665| getExpr(): [Literal] 0
# 2665| Type = [NullPointerType] decltype(nullptr)
# 2665| Value = [Literal] 0
# 2665| ValueCategory = prvalue
# 2665| getExpr().getFullyConverted(): [CStyleCast] (int *)...
# 2665| Conversion = [PointerConversion] pointer conversion
# 2665| Type = [IntPointerType] int *
# 2665| Value = [CStyleCast] 0
# 2665| ValueCategory = prvalue
# 2666| getStmt(1): [IfStmt] if (...) ...
# 2666| getCondition(): [VariableAccess] b
# 2666| Type = [BoolType] bool
# 2666| ValueCategory = prvalue(load)
# 2666| getThen(): [BlockStmt] { ... }
# 2667| getStmt(0): [DeclStmt] declaration
# 2667| getDeclarationEntry(0): [VariableDeclarationEntry] definition of intBuffer
# 2667| Type = [IntType] int
# 2667| getVariable().getInitializer(): [Initializer] initializer for intBuffer
# 2667| getExpr(): [Literal] 8
# 2667| Type = [IntType] int
# 2667| Value = [Literal] 8
# 2667| ValueCategory = prvalue
# 2668| getStmt(1): [ExprStmt] ExprStmt
# 2668| getExpr(): [AssignExpr] ... = ...
# 2668| Type = [IntPointerType] int *
# 2668| ValueCategory = lvalue
# 2668| getLValue(): [VariableAccess] data
# 2668| Type = [IntPointerType] int *
# 2668| ValueCategory = lvalue
# 2668| getRValue(): [AddressOfExpr] & ...
# 2668| Type = [IntPointerType] int *
# 2668| ValueCategory = prvalue
# 2668| getOperand(): [VariableAccess] intBuffer
# 2668| Type = [IntType] int
# 2668| ValueCategory = lvalue
# 2670| getStmt(2): [ExprStmt] ExprStmt
# 2670| getExpr(): [FunctionCall] call to use_int
# 2670| Type = [VoidType] void
# 2670| ValueCategory = prvalue
# 2670| getArgument(0): [PointerDereferenceExpr] * ...
# 2670| Type = [IntType] int
# 2670| ValueCategory = prvalue(load)
# 2670| getOperand(): [VariableAccess] data
# 2670| Type = [IntPointerType] int *
# 2670| ValueCategory = prvalue(load)
# 2671| getStmt(3): [ReturnStmt] return ...
# 2673| [TopLevelFunction] void use(char const*)
# 2673| <params>:
# 2673| getParameter(0): [Parameter] fmt
# 2673| Type = [PointerType] const char *
# 2684| [TopLevelFunction] void test(bool)
# 2684| <params>:
# 2684| getParameter(0): [Parameter] b
# 2684| Type = [BoolType] bool
# 2685| getEntryPoint(): [BlockStmt] { ... }
# 2686| getStmt(0): [DoStmt] do (...) ...
# 2686| getCondition(): [Literal] 0
# 2686| Type = [IntType] int
# 2686| Value = [Literal] 0
# 2686| ValueCategory = prvalue
# 2686| getStmt(): [BlockStmt] { ... }
# 2686| getStmt(0): [ExprStmt] ExprStmt
# 2686| getExpr(): [FunctionCall] call to use
# 2686| Type = [VoidType] void
# 2686| ValueCategory = prvalue
# 2686| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getCondition(): [VariableAccess] b
# 2686| Type = [BoolType] bool
# 2686| ValueCategory = prvalue(load)
# 2686| getThen():
# 2686| Type = [ArrayType] const char[1]
# 2686| Value = [StringLiteral] ""
# 2686| ValueCategory = lvalue
# 2686| getElse():
# 2686| Type = [ArrayType] const char[1]
# 2686| Value = [StringLiteral] ""
# 2686| ValueCategory = lvalue
# 2686| getThen().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getElse().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getStmt(1): [ExprStmt] ExprStmt
# 2686| getExpr(): [FunctionCall] call to use
# 2686| Type = [VoidType] void
# 2686| ValueCategory = prvalue
# 2686| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getCondition(): [VariableAccess] b
# 2686| Type = [BoolType] bool
# 2686| ValueCategory = prvalue(load)
# 2686| getThen():
# 2686| Type = [ArrayType] const char[1]
# 2686| Value = [StringLiteral] ""
# 2686| ValueCategory = lvalue
# 2686| getElse():
# 2686| Type = [ArrayType] const char[1]
# 2686| Value = [StringLiteral] ""
# 2686| ValueCategory = lvalue
# 2686| getThen().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getElse().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 2686| Type = [PointerType] const char *
# 2686| ValueCategory = prvalue
# 2686| getCondition().getFullyConverted(): [CStyleCast] (bool)...
# 2686| Conversion = [BoolConversion] conversion to bool
# 2686| Type = [BoolType] bool
# 2686| Value = [CStyleCast] 0
# 2686| ValueCategory = prvalue
# 2687| getStmt(1): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -5263,20 +5263,23 @@ ir.cpp:
# 486| void Conditional_LValue(bool)
# 486| Block 0
# 486| v486_1(void) = EnterFunction :
# 486| m486_2(unknown) = AliasedDefinition :
# 486| m486_3(unknown) = InitializeNonLocal :
# 486| m486_4(unknown) = Chi : total:m486_2, partial:m486_3
# 486| r486_5(glval<bool>) = VariableAddress[a] :
# 486| m486_6(bool) = InitializeParameter[a] : &:r486_5
# 487| r487_1(glval<int>) = VariableAddress[x] :
# 487| m487_2(int) = Uninitialized[x] : &:r487_1
# 488| r488_1(glval<int>) = VariableAddress[y] :
# 488| m488_2(int) = Uninitialized[y] : &:r488_1
# 489| r489_1(int) = Constant[5] :
# 489| r489_2(glval<bool>) = VariableAddress[a] :
# 489| r489_3(bool) = Load[a] : &:r489_2, m486_6
# 489| v489_4(void) = ConditionalBranch : r489_3
# 486| v486_1(void) = EnterFunction :
# 486| m486_2(unknown) = AliasedDefinition :
# 486| m486_3(unknown) = InitializeNonLocal :
# 486| m486_4(unknown) = Chi : total:m486_2, partial:m486_3
# 486| m486_5(int) = UninitializedGroup[x,y] :
# 486| r486_6(glval<bool>) = VariableAddress[a] :
# 486| m486_7(bool) = InitializeParameter[a] : &:r486_6
# 487| r487_1(glval<int>) = VariableAddress[x] :
# 487| m487_2(int) = Uninitialized[x] : &:r487_1
# 487| m487_3(int) = Chi : total:m486_5, partial:m487_2
# 488| r488_1(glval<int>) = VariableAddress[y] :
# 488| m488_2(int) = Uninitialized[y] : &:r488_1
# 488| m488_3(int) = Chi : total:m487_3, partial:m488_2
# 489| r489_1(int) = Constant[5] :
# 489| r489_2(glval<bool>) = VariableAddress[a] :
# 489| r489_3(bool) = Load[a] : &:r489_2, m486_7
# 489| v489_4(void) = ConditionalBranch : r489_3
#-----| False -> Block 3
#-----| True -> Block 2
@@ -5285,11 +5288,11 @@ ir.cpp:
# 489| r489_6(glval<unknown>) = VariableAddress[#temp489:6] :
# 489| r489_7(glval<int>) = Load[#temp489:6] : &:r489_6, m489_5
# 489| m489_8(int) = Store[?] : &:r489_7, r489_1
# 489| m489_9(unknown) = Chi : total:m486_4, partial:m489_8
# 489| m489_9(int) = Chi : total:m488_3, partial:m489_8
# 490| v490_1(void) = NoOp :
# 486| v486_7(void) = ReturnVoid :
# 486| v486_8(void) = AliasedUse : ~m489_9
# 486| v486_9(void) = ExitFunction :
# 486| v486_8(void) = ReturnVoid :
# 486| v486_9(void) = AliasedUse : m486_3
# 486| v486_10(void) = ExitFunction :
# 489| Block 2
# 489| r489_10(glval<int>) = VariableAddress[x] :
@@ -14072,21 +14075,24 @@ ir.cpp:
# 2059| void TernaryTestInt(bool, int, int, int)
# 2059| Block 0
# 2059| v2059_1(void) = EnterFunction :
# 2059| m2059_2(unknown) = AliasedDefinition :
# 2059| m2059_3(unknown) = InitializeNonLocal :
# 2059| m2059_4(unknown) = Chi : total:m2059_2, partial:m2059_3
# 2059| r2059_5(glval<bool>) = VariableAddress[a] :
# 2059| m2059_6(bool) = InitializeParameter[a] : &:r2059_5
# 2059| r2059_7(glval<int>) = VariableAddress[x] :
# 2059| m2059_8(int) = InitializeParameter[x] : &:r2059_7
# 2059| r2059_9(glval<int>) = VariableAddress[y] :
# 2059| m2059_10(int) = InitializeParameter[y] : &:r2059_9
# 2059| r2059_11(glval<int>) = VariableAddress[z] :
# 2059| m2059_12(int) = InitializeParameter[z] : &:r2059_11
# 2060| r2060_1(glval<bool>) = VariableAddress[a] :
# 2060| r2060_2(bool) = Load[a] : &:r2060_1, m2059_6
# 2060| v2060_3(void) = ConditionalBranch : r2060_2
# 2059| v2059_1(void) = EnterFunction :
# 2059| m2059_2(unknown) = AliasedDefinition :
# 2059| m2059_3(unknown) = InitializeNonLocal :
# 2059| m2059_4(unknown) = Chi : total:m2059_2, partial:m2059_3
# 2059| m2059_5(int) = UninitializedGroup[x,y] :
# 2059| r2059_6(glval<bool>) = VariableAddress[a] :
# 2059| m2059_7(bool) = InitializeParameter[a] : &:r2059_6
# 2059| r2059_8(glval<int>) = VariableAddress[x] :
# 2059| m2059_9(int) = InitializeParameter[x] : &:r2059_8
# 2059| m2059_10(int) = Chi : total:m2059_5, partial:m2059_9
# 2059| r2059_11(glval<int>) = VariableAddress[y] :
# 2059| m2059_12(int) = InitializeParameter[y] : &:r2059_11
# 2059| m2059_13(int) = Chi : total:m2059_10, partial:m2059_12
# 2059| r2059_14(glval<int>) = VariableAddress[z] :
# 2059| m2059_15(int) = InitializeParameter[z] : &:r2059_14
# 2060| r2060_1(glval<bool>) = VariableAddress[a] :
# 2060| r2060_2(bool) = Load[a] : &:r2060_1, m2059_7
# 2060| v2060_3(void) = ConditionalBranch : r2060_2
#-----| False -> Block 3
#-----| True -> Block 2
@@ -14097,21 +14103,21 @@ ir.cpp:
# 2060| r2060_7(glval<int>) = VariableAddress[z] :
# 2060| m2060_8(int) = Store[z] : &:r2060_7, r2060_6
# 2061| r2061_1(glval<bool>) = VariableAddress[a] :
# 2061| r2061_2(bool) = Load[a] : &:r2061_1, m2059_6
# 2061| r2061_2(bool) = Load[a] : &:r2061_1, m2059_7
# 2061| v2061_3(void) = ConditionalBranch : r2061_2
#-----| False -> Block 6
#-----| True -> Block 5
# 2060| Block 2
# 2060| r2060_9(glval<int>) = VariableAddress[x] :
# 2060| r2060_10(int) = Load[x] : &:r2060_9, m2059_8
# 2060| r2060_10(int) = Load[x] : &:r2060_9, m2059_9
# 2060| r2060_11(glval<int>) = VariableAddress[#temp2060:9] :
# 2060| m2060_12(int) = Store[#temp2060:9] : &:r2060_11, r2060_10
#-----| Goto -> Block 1
# 2060| Block 3
# 2060| r2060_13(glval<int>) = VariableAddress[y] :
# 2060| r2060_14(int) = Load[y] : &:r2060_13, m2059_10
# 2060| r2060_14(int) = Load[y] : &:r2060_13, m2059_12
# 2060| r2060_15(glval<int>) = VariableAddress[#temp2060:9] :
# 2060| m2060_16(int) = Store[#temp2060:9] : &:r2060_15, r2060_14
#-----| Goto -> Block 1
@@ -14123,14 +14129,14 @@ ir.cpp:
# 2061| r2061_7(glval<int>) = VariableAddress[z] :
# 2061| m2061_8(int) = Store[z] : &:r2061_7, r2061_6
# 2062| r2062_1(glval<bool>) = VariableAddress[a] :
# 2062| r2062_2(bool) = Load[a] : &:r2062_1, m2059_6
# 2062| r2062_2(bool) = Load[a] : &:r2062_1, m2059_7
# 2062| v2062_3(void) = ConditionalBranch : r2062_2
#-----| False -> Block 9
#-----| True -> Block 8
# 2061| Block 5
# 2061| r2061_9(glval<int>) = VariableAddress[x] :
# 2061| r2061_10(int) = Load[x] : &:r2061_9, m2059_8
# 2061| r2061_10(int) = Load[x] : &:r2061_9, m2059_9
# 2061| r2061_11(glval<int>) = VariableAddress[#temp2061:9] :
# 2061| m2061_12(int) = Store[#temp2061:9] : &:r2061_11, r2061_10
#-----| Goto -> Block 4
@@ -14149,7 +14155,7 @@ ir.cpp:
# 2062| m2062_8(int) = Store[z] : &:r2062_7, r2062_6
# 2063| r2063_1(int) = Constant[7] :
# 2063| r2063_2(glval<bool>) = VariableAddress[a] :
# 2063| r2063_3(bool) = Load[a] : &:r2063_2, m2059_6
# 2063| r2063_3(bool) = Load[a] : &:r2063_2, m2059_7
# 2063| v2063_4(void) = ConditionalBranch : r2063_3
#-----| False -> Block 12
#-----| True -> Block 11
@@ -14171,11 +14177,11 @@ ir.cpp:
# 2063| r2063_6(glval<unknown>) = VariableAddress[#temp2063:6] :
# 2063| r2063_7(glval<int>) = Load[#temp2063:6] : &:r2063_6, m2063_5
# 2063| m2063_8(int) = Store[?] : &:r2063_7, r2063_1
# 2063| m2063_9(unknown) = Chi : total:m2059_4, partial:m2063_8
# 2063| m2063_9(int) = Chi : total:m2059_13, partial:m2063_8
# 2064| v2064_1(void) = NoOp :
# 2059| v2059_13(void) = ReturnVoid :
# 2059| v2059_14(void) = AliasedUse : ~m2063_9
# 2059| v2059_15(void) = ExitFunction :
# 2059| v2059_16(void) = ReturnVoid :
# 2059| v2059_17(void) = AliasedUse : m2059_3
# 2059| v2059_18(void) = ExitFunction :
# 2063| Block 11
# 2063| r2063_10(glval<int>) = VariableAddress[x] :
@@ -14419,18 +14425,21 @@ ir.cpp:
# 2080| m2080_2(unknown) = AliasedDefinition :
# 2080| m2080_3(unknown) = InitializeNonLocal :
# 2080| m2080_4(unknown) = Chi : total:m2080_2, partial:m2080_3
# 2080| r2080_5(glval<bool>) = VariableAddress[a] :
# 2080| m2080_6(bool) = InitializeParameter[a] : &:r2080_5
# 2080| r2080_7(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2080| m2080_8(TernaryNonPodObj) = InitializeParameter[x] : &:r2080_7
# 2080| r2080_9(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2080| m2080_10(TernaryNonPodObj) = InitializeParameter[y] : &:r2080_9
# 2080| r2080_11(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2080| m2080_12(TernaryNonPodObj) = InitializeParameter[z] : &:r2080_11
# 2080| m2080_5(unknown) = UninitializedGroup[x,y] :
# 2080| r2080_6(glval<bool>) = VariableAddress[a] :
# 2080| m2080_7(bool) = InitializeParameter[a] : &:r2080_6
# 2080| r2080_8(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2080| m2080_9(TernaryNonPodObj) = InitializeParameter[x] : &:r2080_8
# 2080| m2080_10(unknown) = Chi : total:m2080_5, partial:m2080_9
# 2080| r2080_11(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2080| m2080_12(TernaryNonPodObj) = InitializeParameter[y] : &:r2080_11
# 2080| m2080_13(unknown) = Chi : total:m2080_10, partial:m2080_12
# 2080| r2080_14(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2080| m2080_15(TernaryNonPodObj) = InitializeParameter[z] : &:r2080_14
# 2081| r2081_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2081| r2081_2(glval<unknown>) = FunctionAddress[operator=] :
# 2081| r2081_3(glval<bool>) = VariableAddress[a] :
# 2081| r2081_4(bool) = Load[a] : &:r2081_3, m2080_6
# 2081| r2081_4(bool) = Load[a] : &:r2081_3, m2080_7
# 2081| v2081_5(void) = ConditionalBranch : r2081_4
#-----| False -> Block 3
#-----| True -> Block 2
@@ -14444,16 +14453,16 @@ ir.cpp:
# 2081| r2081_11(TernaryNonPodObj &) = Call[operator=] : func:r2081_2, this:r2081_1, 0:r2081_10
# 2081| m2081_12(unknown) = ^CallSideEffect : ~m2080_4
# 2081| m2081_13(unknown) = Chi : total:m2080_4, partial:m2081_12
# 2081| v2081_14(void) = ^IndirectReadSideEffect[-1] : &:r2081_1, m2080_12
# 2081| v2081_15(void) = ^BufferReadSideEffect[0] : &:r2081_10, ~m2081_13
# 2081| v2081_14(void) = ^IndirectReadSideEffect[-1] : &:r2081_1, m2080_15
# 2081| v2081_15(void) = ^BufferReadSideEffect[0] : &:r2081_10, ~m2080_13
# 2081| m2081_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2081_1
# 2081| m2081_17(TernaryNonPodObj) = Chi : total:m2080_12, partial:m2081_16
# 2081| m2081_17(TernaryNonPodObj) = Chi : total:m2080_15, partial:m2081_16
# 2081| r2081_18(glval<TernaryNonPodObj>) = CopyValue : r2081_11
# 2082| r2082_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2082| r2082_2(glval<unknown>) = FunctionAddress[operator=] :
# 2082| r2082_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2082:9] :
# 2082| r2082_4(glval<bool>) = VariableAddress[a] :
# 2082| r2082_5(bool) = Load[a] : &:r2082_4, m2080_6
# 2082| r2082_5(bool) = Load[a] : &:r2082_4, m2080_7
# 2082| v2082_6(void) = ConditionalBranch : r2082_5
#-----| False -> Block 6
#-----| True -> Block 5
@@ -14499,7 +14508,7 @@ ir.cpp:
# 2083| r2083_2(glval<unknown>) = FunctionAddress[operator=] :
# 2083| r2083_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2083:9] :
# 2083| r2083_4(glval<bool>) = VariableAddress[a] :
# 2083| r2083_5(bool) = Load[a] : &:r2083_4, m2080_6
# 2083| r2083_5(bool) = Load[a] : &:r2083_4, m2080_7
# 2083| v2083_6(void) = ConditionalBranch : r2083_5
#-----| False -> Block 9
#-----| True -> Block 8
@@ -14514,7 +14523,7 @@ ir.cpp:
# 2082| v2082_37(void) = Call[TernaryNonPodObj] : func:r2082_33, this:r2082_31, 0:r2082_36
# 2082| m2082_38(unknown) = ^CallSideEffect : ~m2081_13
# 2082| m2082_39(unknown) = Chi : total:m2081_13, partial:m2082_38
# 2082| v2082_40(void) = ^BufferReadSideEffect[0] : &:r2082_36, ~m2080_8
# 2082| v2082_40(void) = ^BufferReadSideEffect[0] : &:r2082_36, ~m2080_9
# 2082| m2082_41(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2082_31
# 2082| m2082_42(TernaryNonPodObj) = Chi : total:m2082_32, partial:m2082_41
# 2082| r2082_43(TernaryNonPodObj) = Load[#temp2082:13] : &:r2082_31, m2082_42
@@ -14564,7 +14573,7 @@ ir.cpp:
# 2084| r2084_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2084| r2084_2(glval<unknown>) = FunctionAddress[operator=] :
# 2084| r2084_3(glval<bool>) = VariableAddress[a] :
# 2084| r2084_4(bool) = Load[a] : &:r2084_3, m2080_6
# 2084| r2084_4(bool) = Load[a] : &:r2084_3, m2080_7
# 2084| v2084_5(void) = ConditionalBranch : r2084_4
#-----| False -> Block 12
#-----| True -> Block 11
@@ -14607,7 +14616,7 @@ ir.cpp:
# 2084| m2084_12(unknown) = ^CallSideEffect : ~m2083_29
# 2084| m2084_13(unknown) = Chi : total:m2083_29, partial:m2084_12
# 2084| v2084_14(void) = ^IndirectReadSideEffect[-1] : &:r2084_1, m2083_21
# 2084| v2084_15(void) = ^BufferReadSideEffect[0] : &:r2084_10, ~m2084_13
# 2084| v2084_15(void) = ^BufferReadSideEffect[0] : &:r2084_10, ~m2080_13
# 2084| m2084_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2084_1
# 2084| m2084_17(TernaryNonPodObj) = Chi : total:m2083_21, partial:m2084_16
# 2084| r2084_18(glval<TernaryNonPodObj>) = CopyValue : r2084_11
@@ -14640,9 +14649,9 @@ ir.cpp:
# 2084| m2084_45(unknown) = Chi : total:m2084_42, partial:m2084_44
# 2084| r2084_46(glval<TernaryNonPodObj>) = CopyValue : r2084_31
# 2085| v2085_1(void) = NoOp :
# 2080| v2080_13(void) = ReturnVoid :
# 2080| v2080_14(void) = AliasedUse : ~m2084_42
# 2080| v2080_15(void) = ExitFunction :
# 2080| v2080_16(void) = ReturnVoid :
# 2080| v2080_17(void) = AliasedUse : ~m2084_42
# 2080| v2080_18(void) = ExitFunction :
# 2084| Block 11
# 2084| r2084_47(glval<TernaryNonPodObj>) = VariableAddress[x] :
@@ -18395,6 +18404,534 @@ ir.cpp:
# 2555| v2555_8(void) = AliasedUse : m2555_3
# 2555| v2555_9(void) = ExitFunction :
# 2559| void p_points_to_x_or_y(int, int)
# 2559| Block 0
# 2559| v2559_1(void) = EnterFunction :
# 2559| m2559_2(unknown) = AliasedDefinition :
# 2559| m2559_3(unknown) = InitializeNonLocal :
# 2559| m2559_4(unknown) = Chi : total:m2559_2, partial:m2559_3
# 2559| m2559_5(int) = UninitializedGroup[x,y] :
# 2559| r2559_6(glval<int>) = VariableAddress[a] :
# 2559| m2559_7(int) = InitializeParameter[a] : &:r2559_6
# 2559| r2559_8(glval<int>) = VariableAddress[b] :
# 2559| m2559_9(int) = InitializeParameter[b] : &:r2559_8
# 2560| r2560_1(glval<int>) = VariableAddress[x] :
# 2560| m2560_2(int) = Uninitialized[x] : &:r2560_1
# 2560| m2560_3(int) = Chi : total:m2559_5, partial:m2560_2
# 2561| r2561_1(glval<int>) = VariableAddress[y] :
# 2561| m2561_2(int) = Uninitialized[y] : &:r2561_1
# 2561| m2561_3(int) = Chi : total:m2560_3, partial:m2561_2
# 2562| r2562_1(glval<int *>) = VariableAddress[p] :
# 2562| m2562_2(int *) = Uninitialized[p] : &:r2562_1
# 2563| r2563_1(glval<int>) = VariableAddress[a] :
# 2563| r2563_2(int) = Load[a] : &:r2563_1, m2559_7
# 2563| r2563_3(glval<int>) = VariableAddress[b] :
# 2563| r2563_4(int) = Load[b] : &:r2563_3, m2559_9
# 2563| r2563_5(bool) = CompareLT : r2563_2, r2563_4
# 2563| v2563_6(void) = ConditionalBranch : r2563_5
#-----| False -> Block 2
#-----| True -> Block 1
# 2564| Block 1
# 2564| r2564_1(glval<int>) = VariableAddress[x] :
# 2564| r2564_2(int *) = CopyValue : r2564_1
# 2564| r2564_3(glval<int *>) = VariableAddress[p] :
# 2564| m2564_4(int *) = Store[p] : &:r2564_3, r2564_2
#-----| Goto -> Block 3
# 2566| Block 2
# 2566| r2566_1(glval<int>) = VariableAddress[y] :
# 2566| r2566_2(int *) = CopyValue : r2566_1
# 2566| r2566_3(glval<int *>) = VariableAddress[p] :
# 2566| m2566_4(int *) = Store[p] : &:r2566_3, r2566_2
#-----| Goto -> Block 3
# 2568| Block 3
# 2568| m2568_1(int *) = Phi : from 1:m2564_4, from 2:m2566_4
# 2568| r2568_2(int) = Constant[5] :
# 2568| r2568_3(glval<int *>) = VariableAddress[p] :
# 2568| r2568_4(int *) = Load[p] : &:r2568_3, m2568_1
# 2568| r2568_5(glval<int>) = CopyValue : r2568_4
# 2568| m2568_6(int) = Store[?] : &:r2568_5, r2568_2
# 2568| m2568_7(int) = Chi : total:m2561_3, partial:m2568_6
# 2569| r2569_1(glval<int>) = VariableAddress[z] :
# 2569| r2569_2(glval<int>) = VariableAddress[x] :
# 2569| r2569_3(int) = Load[x] : &:r2569_2, ~m2568_7
# 2569| m2569_4(int) = Store[z] : &:r2569_1, r2569_3
# 2570| r2570_1(glval<int>) = VariableAddress[w] :
# 2570| r2570_2(glval<int>) = VariableAddress[y] :
# 2570| r2570_3(int) = Load[y] : &:r2570_2, ~m2568_7
# 2570| m2570_4(int) = Store[w] : &:r2570_1, r2570_3
# 2571| v2571_1(void) = NoOp :
# 2559| v2559_10(void) = ReturnVoid :
# 2559| v2559_11(void) = AliasedUse : m2559_3
# 2559| v2559_12(void) = ExitFunction :
# 2573| int phi_after_while()
# 2573| Block 0
# 2573| v2573_1(void) = EnterFunction :
# 2573| m2573_2(unknown) = AliasedDefinition :
# 2573| m2573_3(unknown) = InitializeNonLocal :
# 2573| m2573_4(unknown) = Chi : total:m2573_2, partial:m2573_3
# 2573| m2573_5(int) = UninitializedGroup[r,s] :
# 2574| r2574_1(glval<int>) = VariableAddress[r] :
# 2574| m2574_2(int) = Uninitialized[r] : &:r2574_1
# 2574| m2574_3(int) = Chi : total:m2573_5, partial:m2574_2
# 2575| r2575_1(glval<int *>) = VariableAddress[rP] :
# 2575| r2575_2(glval<int>) = VariableAddress[r] :
# 2575| r2575_3(int *) = CopyValue : r2575_2
# 2575| m2575_4(int *) = Store[rP] : &:r2575_1, r2575_3
#-----| Goto -> Block 1
# 2577| Block 1
# 2577| m2577_1(int) = Phi : from 0:m2574_3, from 2:m2579_7
# 2577| m2577_2(unknown) = Phi : from 0:~m2573_4, from 2:~m2577_7
# 2577| m2577_3(int *) = Phi : from 0:m2575_4, from 2:m2580_4
# 2577| r2577_4(glval<unknown>) = FunctionAddress[predicateA] :
# 2577| r2577_5(bool) = Call[predicateA] : func:r2577_4
# 2577| m2577_6(unknown) = ^CallSideEffect : ~m2577_2
# 2577| m2577_7(unknown) = Chi : total:m2577_2, partial:m2577_6
# 2577| v2577_8(void) = ConditionalBranch : r2577_5
#-----| False -> Block 3
#-----| True -> Block 2
# 2578| Block 2
# 2578| r2578_1(glval<int>) = VariableAddress[s] :
# 2578| r2578_2(int) = Constant[0] :
# 2578| m2578_3(int) = Store[s] : &:r2578_1, r2578_2
# 2578| m2578_4(int) = Chi : total:m2577_1, partial:m2578_3
# 2579| r2579_1(glval<int>) = VariableAddress[s] :
# 2579| r2579_2(int) = Load[s] : &:r2579_1, m2578_3
# 2579| r2579_3(glval<int *>) = VariableAddress[rP] :
# 2579| r2579_4(int *) = Load[rP] : &:r2579_3, m2577_3
# 2579| r2579_5(glval<int>) = CopyValue : r2579_4
# 2579| m2579_6(int) = Store[?] : &:r2579_5, r2579_2
# 2579| m2579_7(int) = Chi : total:m2578_4, partial:m2579_6
# 2580| r2580_1(glval<int>) = VariableAddress[s] :
# 2580| r2580_2(int *) = CopyValue : r2580_1
# 2580| r2580_3(glval<int *>) = VariableAddress[rP] :
# 2580| m2580_4(int *) = Store[rP] : &:r2580_3, r2580_2
#-----| Goto (back edge) -> Block 1
# 2583| Block 3
# 2583| r2583_1(glval<int>) = VariableAddress[#return] :
# 2583| r2583_2(glval<int>) = VariableAddress[r] :
# 2583| r2583_3(int) = Load[r] : &:r2583_2, ~m2577_1
# 2583| m2583_4(int) = Store[#return] : &:r2583_1, r2583_3
# 2573| r2573_6(glval<int>) = VariableAddress[#return] :
# 2573| v2573_7(void) = ReturnValue : &:r2573_6, m2583_4
# 2573| v2573_8(void) = AliasedUse : ~m2577_7
# 2573| v2573_9(void) = ExitFunction :
# 2588| char* recursive_conditional_call_with_increment(char*, bool)
# 2588| Block 0
# 2588| v2588_1(void) = EnterFunction :
# 2588| m2588_2(unknown) = AliasedDefinition :
# 2588| m2588_3(unknown) = InitializeNonLocal :
# 2588| m2588_4(unknown) = Chi : total:m2588_2, partial:m2588_3
# 2588| r2588_5(glval<char *>) = VariableAddress[d] :
# 2588| m2588_6(char *) = InitializeParameter[d] : &:r2588_5
# 2588| r2588_7(char *) = Load[d] : &:r2588_5, m2588_6
# 2588| m2588_8(unknown) = InitializeIndirection[d] : &:r2588_7
# 2588| r2588_9(glval<bool>) = VariableAddress[b] :
# 2588| m2588_10(bool) = InitializeParameter[b] : &:r2588_9
# 2590| r2590_1(glval<bool>) = VariableAddress[b] :
# 2590| r2590_2(bool) = Load[b] : &:r2590_1, m2588_10
# 2590| v2590_3(void) = ConditionalBranch : r2590_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2591| Block 1
# 2591| r2591_1(glval<unknown>) = FunctionAddress[recursive_conditional_call_with_increment] :
# 2591| r2591_2(glval<char *>) = VariableAddress[d] :
# 2591| r2591_3(char *) = Load[d] : &:r2591_2, m2588_6
# 2591| r2591_4(glval<bool>) = VariableAddress[b] :
# 2591| r2591_5(bool) = Load[b] : &:r2591_4, m2588_10
# 2591| r2591_6(char *) = Call[recursive_conditional_call_with_increment] : func:r2591_1, 0:r2591_3, 1:r2591_5
# 2591| m2591_7(unknown) = ^CallSideEffect : ~m2588_4
# 2591| m2591_8(unknown) = Chi : total:m2588_4, partial:m2591_7
# 2591| v2591_9(void) = ^BufferReadSideEffect[0] : &:r2591_3, ~m2588_8
# 2591| m2591_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r2591_3
# 2591| m2591_11(unknown) = Chi : total:m2588_8, partial:m2591_10
# 2591| r2591_12(glval<char *>) = VariableAddress[d] :
# 2591| m2591_13(char *) = Store[d] : &:r2591_12, r2591_6
#-----| Goto -> Block 2
# 2593| Block 2
# 2593| m2593_1(unknown) = Phi : from 0:m2588_8, from 1:m2591_11
# 2593| m2593_2(unknown) = Phi : from 0:~m2588_4, from 1:~m2591_8
# 2593| m2593_3(char *) = Phi : from 0:m2588_6, from 1:m2591_13
# 2593| r2593_4(glval<char *>) = VariableAddress[d] :
# 2593| r2593_5(char *) = Load[d] : &:r2593_4, m2593_3
# 2593| r2593_6(int) = Constant[1] :
# 2593| r2593_7(char *) = PointerAdd[1] : r2593_5, r2593_6
# 2593| m2593_8(char *) = Store[d] : &:r2593_4, r2593_7
# 2594| r2594_1(glval<char *>) = VariableAddress[#return] :
# 2594| r2594_2(glval<char *>) = VariableAddress[d] :
# 2594| r2594_3(char *) = Load[d] : &:r2594_2, m2593_8
# 2594| m2594_4(char *) = Store[#return] : &:r2594_1, r2594_3
# 2588| v2588_11(void) = ReturnIndirection[d] : &:r2588_7, m2593_1
# 2588| r2588_12(glval<char *>) = VariableAddress[#return] :
# 2588| v2588_13(void) = ReturnValue : &:r2588_12, m2594_4
# 2588| v2588_14(void) = AliasedUse : ~m2593_2
# 2588| v2588_15(void) = ExitFunction :
# 2602| Recursive* merge(Recursive*)
# 2602| Block 0
# 2602| v2602_1(void) = EnterFunction :
# 2602| m2602_2(unknown) = AliasedDefinition :
# 2602| m2602_3(unknown) = InitializeNonLocal :
# 2602| m2602_4(unknown) = Chi : total:m2602_2, partial:m2602_3
# 2602| m2602_5(Recursive *) = UninitializedGroup[a,b] :
# 2602| m2602_6(unknown) = Chi : total:m2602_4, partial:m2602_5
# 2602| r2602_7(glval<Recursive *>) = VariableAddress[a] :
# 2602| m2602_8(Recursive *) = InitializeParameter[a] : &:r2602_7
# 2602| r2602_9(Recursive *) = Load[a] : &:r2602_7, m2602_8
# 2602| m2602_10(unknown) = InitializeIndirection[a] : &:r2602_9
# 2602| m2602_11(unknown) = Chi : total:m2602_6, partial:m2602_10
# 2604| r2604_1(glval<Recursive *>) = VariableAddress[b] :
# 2604| m2604_2(Recursive *) = Uninitialized[b] : &:r2604_1
# 2604| m2604_3(unknown) = Chi : total:m2602_11, partial:m2604_2
# 2605| r2605_1(glval<Recursive **>) = VariableAddress[p] :
# 2605| r2605_2(glval<Recursive *>) = VariableAddress[b] :
# 2605| r2605_3(Recursive **) = CopyValue : r2605_2
# 2605| m2605_4(Recursive **) = Store[p] : &:r2605_1, r2605_3
#-----| Goto -> Block 1
# 2607| Block 1
# 2607| m2607_1(unknown) = Phi : from 0:~m2604_3, from 2:~m2609_7
# 2607| m2607_2(Recursive **) = Phi : from 0:m2605_4, from 2:m2610_6
# 2607| r2607_3(glval<unknown>) = FunctionAddress[predicateA] :
# 2607| r2607_4(bool) = Call[predicateA] : func:r2607_3
# 2607| m2607_5(unknown) = ^CallSideEffect : ~m2607_1
# 2607| m2607_6(unknown) = Chi : total:m2607_1, partial:m2607_5
# 2607| v2607_7(void) = ConditionalBranch : r2607_4
#-----| False -> Block 3
#-----| True -> Block 2
# 2609| Block 2
# 2609| r2609_1(glval<Recursive *>) = VariableAddress[a] :
# 2609| r2609_2(Recursive *) = Load[a] : &:r2609_1, m2602_8
# 2609| r2609_3(glval<Recursive **>) = VariableAddress[p] :
# 2609| r2609_4(Recursive **) = Load[p] : &:r2609_3, m2607_2
# 2609| r2609_5(glval<Recursive *>) = CopyValue : r2609_4
# 2609| m2609_6(Recursive *) = Store[?] : &:r2609_5, r2609_2
# 2609| m2609_7(unknown) = Chi : total:m2607_6, partial:m2609_6
# 2610| r2610_1(glval<Recursive *>) = VariableAddress[a] :
# 2610| r2610_2(Recursive *) = Load[a] : &:r2610_1, m2602_8
# 2610| r2610_3(glval<Recursive *>) = FieldAddress[next] : r2610_2
# 2610| r2610_4(Recursive **) = CopyValue : r2610_3
# 2610| r2610_5(glval<Recursive **>) = VariableAddress[p] :
# 2610| m2610_6(Recursive **) = Store[p] : &:r2610_5, r2610_4
#-----| Goto (back edge) -> Block 1
# 2613| Block 3
# 2613| r2613_1(glval<Recursive *>) = VariableAddress[#return] :
# 2613| r2613_2(glval<Recursive *>) = VariableAddress[b] :
# 2613| r2613_3(Recursive *) = Load[b] : &:r2613_2, ~m2607_6
# 2613| m2613_4(Recursive *) = Store[#return] : &:r2613_1, r2613_3
# 2602| v2602_12(void) = ReturnIndirection[a] : &:r2602_9, ~m2607_6
# 2602| r2602_13(glval<Recursive *>) = VariableAddress[#return] :
# 2602| v2602_14(void) = ReturnValue : &:r2602_13, m2613_4
# 2602| v2602_15(void) = AliasedUse : ~m2607_6
# 2602| v2602_16(void) = ExitFunction :
# 2618| void escaping_pointer(bool)
# 2618| Block 0
# 2618| v2618_1(void) = EnterFunction :
# 2618| m2618_2(unknown) = AliasedDefinition :
# 2618| m2618_3(unknown) = InitializeNonLocal :
# 2618| m2618_4(unknown) = Chi : total:m2618_2, partial:m2618_3
# 2618| m2618_5(unknown) = UninitializedGroup[l1,l2] :
# 2618| m2618_6(unknown) = Chi : total:m2618_4, partial:m2618_5
# 2618| r2618_7(glval<bool>) = VariableAddress[b] :
# 2618| m2618_8(bool) = InitializeParameter[b] : &:r2618_7
# 2620| r2620_1(glval<int *>) = VariableAddress[data] :
# 2620| m2620_2(int *) = Uninitialized[data] : &:r2620_1
# 2621| r2621_1(glval<int>) = VariableAddress[l1] :
# 2621| m2621_2(int) = Uninitialized[l1] : &:r2621_1
# 2621| m2621_3(unknown) = Chi : total:m2618_6, partial:m2621_2
# 2621| r2621_4(glval<int>) = VariableAddress[l2] :
# 2621| m2621_5(int) = Uninitialized[l2] : &:r2621_4
# 2621| m2621_6(unknown) = Chi : total:m2621_3, partial:m2621_5
# 2622| r2622_1(glval<bool>) = VariableAddress[b] :
# 2622| r2622_2(bool) = Load[b] : &:r2622_1, m2618_8
# 2622| v2622_3(void) = ConditionalBranch : r2622_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2624| Block 1
# 2624| r2624_1(glval<int>) = VariableAddress[l1] :
# 2624| r2624_2(int *) = CopyValue : r2624_1
# 2624| r2624_3(glval<int *>) = VariableAddress[data] :
# 2624| m2624_4(int *) = Store[data] : &:r2624_3, r2624_2
#-----| Goto -> Block 3
# 2628| Block 2
# 2628| r2628_1(glval<int>) = VariableAddress[l2] :
# 2628| r2628_2(int *) = CopyValue : r2628_1
# 2628| r2628_3(glval<int *>) = VariableAddress[data] :
# 2628| m2628_4(int *) = Store[data] : &:r2628_3, r2628_2
#-----| Goto -> Block 3
# 2630| Block 3
# 2630| m2630_1(int *) = Phi : from 1:m2624_4, from 2:m2628_4
# 2630| r2630_2(glval<unknown>) = FunctionAddress[use_const_int] :
# 2630| r2630_3(glval<int *>) = VariableAddress[data] :
# 2630| r2630_4(int *) = Load[data] : &:r2630_3, m2630_1
# 2630| r2630_5(int *) = Convert : r2630_4
# 2630| v2630_6(void) = Call[use_const_int] : func:r2630_2, 0:r2630_5
# 2630| m2630_7(unknown) = ^CallSideEffect : ~m2621_6
# 2630| m2630_8(unknown) = Chi : total:m2621_6, partial:m2630_7
# 2630| v2630_9(void) = ^BufferReadSideEffect[0] : &:r2630_5, ~m2630_8
# 2631| v2631_1(void) = NoOp :
# 2618| v2618_9(void) = ReturnVoid :
# 2618| v2618_10(void) = AliasedUse : ~m2630_8
# 2618| v2618_11(void) = ExitFunction :
# 2639| void needs_chi_for_initialize_groups()
# 2639| Block 0
# 2639| v2639_1(void) = EnterFunction :
# 2639| m2639_2(unknown) = AliasedDefinition :
# 2639| m2639_3(unknown) = InitializeNonLocal :
# 2639| m2639_4(unknown) = Chi : total:m2639_2, partial:m2639_3
# 2639| m2639_5(unknown) = UninitializedGroup :
# 2639| m2639_6(unknown) = Chi : total:m2639_4, partial:m2639_5
# 2639| m2639_7(unknown) = UninitializedGroup :
# 2639| m2639_8(unknown) = Chi : total:m2639_6, partial:m2639_7
# 2641| r2641_1(glval<unknown>) = FunctionAddress[predicateA] :
# 2641| r2641_2(bool) = Call[predicateA] : func:r2641_1
# 2641| m2641_3(unknown) = ^CallSideEffect : ~m2639_8
# 2641| m2641_4(unknown) = Chi : total:m2639_8, partial:m2641_3
# 2641| v2641_5(void) = ConditionalBranch : r2641_2
#-----| False -> Block 4
#-----| True -> Block 1
# 2643| Block 1
# 2643| r2643_1(glval<long long *>) = VariableAddress[data] :
# 2643| r2643_2(glval<unknown>) = FunctionAddress[malloc] :
# 2643| r2643_3(unsigned long) = Constant[100] :
# 2643| r2643_4(void *) = Call[malloc] : func:r2643_2, 0:r2643_3
# 2643| m2643_5(unknown) = ^CallSideEffect : ~m2641_4
# 2643| m2643_6(unknown) = Chi : total:m2641_4, partial:m2643_5
# 2643| m2643_7(unknown) = ^InitializeDynamicAllocation : &:r2643_4
# 2643| m2643_8(unknown) = Chi : total:m2643_6, partial:m2643_7
# 2643| r2643_9(long long *) = Convert : r2643_4
# 2643| m2643_10(long long *) = Store[data] : &:r2643_1, r2643_9
# 2644| r2644_1(glval<long long *>) = VariableAddress[data] :
# 2644| r2644_2(long long *) = Load[data] : &:r2644_1, m2643_10
# 2644| r2644_3(void *) = Convert : r2644_2
# 2644| r2644_4(void *) = Constant[0] :
# 2644| r2644_5(bool) = CompareNE : r2644_3, r2644_4
# 2644| v2644_6(void) = ConditionalBranch : r2644_5
#-----| False -> Block 3
#-----| True -> Block 2
# 2646| Block 2
# 2646| r2646_1(glval<unknown>) = FunctionAddress[malloc] :
# 2646| r2646_2(unsigned long) = Constant[100] :
# 2646| r2646_3(void *) = Call[malloc] : func:r2646_1, 0:r2646_2
# 2646| m2646_4(unknown) = ^CallSideEffect : ~m2643_8
# 2646| m2646_5(unknown) = Chi : total:m2643_8, partial:m2646_4
# 2646| m2646_6(unknown) = ^InitializeDynamicAllocation : &:r2646_3
# 2646| m2646_7(unknown) = Chi : total:m2646_5, partial:m2646_6
# 2646| r2646_8(long long *) = Convert : r2646_3
# 2646| r2646_9(glval<long long *>) = VariableAddress[data] :
# 2646| m2646_10(long long *) = Store[data] : &:r2646_9, r2646_8
#-----| Goto -> Block 3
# 2648| Block 3
# 2648| m2648_1(unknown) = Phi : from 1:~m2643_8, from 2:~m2646_7
# 2648| m2648_2(long long *) = Phi : from 1:m2643_10, from 2:m2646_10
# 2648| r2648_3(glval<unknown>) = FunctionAddress[use_const_void_pointer] :
# 2648| r2648_4(glval<long long *>) = VariableAddress[data] :
# 2648| r2648_5(long long *) = Load[data] : &:r2648_4, m2648_2
# 2648| r2648_6(void *) = Convert : r2648_5
# 2648| v2648_7(void) = Call[use_const_void_pointer] : func:r2648_3, 0:r2648_6
# 2648| m2648_8(unknown) = ^CallSideEffect : ~m2648_1
# 2648| m2648_9(unknown) = Chi : total:m2648_1, partial:m2648_8
# 2648| v2648_10(void) = ^BufferReadSideEffect[0] : &:r2648_6, ~m2648_9
#-----| Goto -> Block 7
# 2652| Block 4
# 2652| r2652_1(glval<long long *>) = VariableAddress[data] :
# 2652| r2652_2(glval<unknown>) = FunctionAddress[malloc] :
# 2652| r2652_3(unsigned long) = Constant[100] :
# 2652| r2652_4(void *) = Call[malloc] : func:r2652_2, 0:r2652_3
# 2652| m2652_5(unknown) = ^CallSideEffect : ~m2641_4
# 2652| m2652_6(unknown) = Chi : total:m2641_4, partial:m2652_5
# 2652| m2652_7(unknown) = ^InitializeDynamicAllocation : &:r2652_4
# 2652| m2652_8(unknown) = Chi : total:m2652_6, partial:m2652_7
# 2652| r2652_9(long long *) = Convert : r2652_4
# 2652| m2652_10(long long *) = Store[data] : &:r2652_1, r2652_9
# 2653| r2653_1(glval<long long *>) = VariableAddress[data] :
# 2653| r2653_2(long long *) = Load[data] : &:r2653_1, m2652_10
# 2653| r2653_3(void *) = Convert : r2653_2
# 2653| r2653_4(void *) = Constant[0] :
# 2653| r2653_5(bool) = CompareNE : r2653_3, r2653_4
# 2653| v2653_6(void) = ConditionalBranch : r2653_5
#-----| False -> Block 6
#-----| True -> Block 5
# 2655| Block 5
# 2655| r2655_1(glval<unknown>) = FunctionAddress[malloc] :
# 2655| r2655_2(unsigned long) = Constant[200] :
# 2655| r2655_3(void *) = Call[malloc] : func:r2655_1, 0:r2655_2
# 2655| m2655_4(unknown) = ^CallSideEffect : ~m2652_8
# 2655| m2655_5(unknown) = Chi : total:m2652_8, partial:m2655_4
# 2655| m2655_6(unknown) = ^InitializeDynamicAllocation : &:r2655_3
# 2655| m2655_7(unknown) = Chi : total:m2655_5, partial:m2655_6
# 2655| r2655_8(long long *) = Convert : r2655_3
# 2655| r2655_9(glval<long long *>) = VariableAddress[data] :
# 2655| m2655_10(long long *) = Store[data] : &:r2655_9, r2655_8
#-----| Goto -> Block 6
# 2657| Block 6
# 2657| m2657_1(unknown) = Phi : from 4:~m2652_8, from 5:~m2655_7
# 2657| m2657_2(long long *) = Phi : from 4:m2652_10, from 5:m2655_10
# 2657| r2657_3(glval<unknown>) = FunctionAddress[use_const_void_pointer] :
# 2657| r2657_4(glval<long long *>) = VariableAddress[data] :
# 2657| r2657_5(long long *) = Load[data] : &:r2657_4, m2657_2
# 2657| r2657_6(void *) = Convert : r2657_5
# 2657| v2657_7(void) = Call[use_const_void_pointer] : func:r2657_3, 0:r2657_6
# 2657| m2657_8(unknown) = ^CallSideEffect : ~m2657_1
# 2657| m2657_9(unknown) = Chi : total:m2657_1, partial:m2657_8
# 2657| v2657_10(void) = ^BufferReadSideEffect[0] : &:r2657_6, ~m2657_9
#-----| Goto -> Block 7
# 2659| Block 7
# 2659| m2659_1(unknown) = Phi : from 3:~m2648_9, from 6:~m2657_9
# 2659| v2659_2(void) = NoOp :
# 2639| v2639_9(void) = ReturnVoid :
# 2639| v2639_10(void) = AliasedUse : ~m2659_1
# 2639| v2639_11(void) = ExitFunction :
# 2663| void phi_with_single_input_at_merge(bool)
# 2663| Block 0
# 2663| v2663_1(void) = EnterFunction :
# 2663| m2663_2(unknown) = AliasedDefinition :
# 2663| m2663_3(unknown) = InitializeNonLocal :
# 2663| m2663_4(unknown) = Chi : total:m2663_2, partial:m2663_3
# 2663| r2663_5(glval<bool>) = VariableAddress[b] :
# 2663| m2663_6(bool) = InitializeParameter[b] : &:r2663_5
# 2665| r2665_1(glval<int *>) = VariableAddress[data] :
# 2665| r2665_2(int *) = Constant[0] :
# 2665| m2665_3(int *) = Store[data] : &:r2665_1, r2665_2
# 2666| r2666_1(glval<bool>) = VariableAddress[b] :
# 2666| r2666_2(bool) = Load[b] : &:r2666_1, m2663_6
# 2666| v2666_3(void) = ConditionalBranch : r2666_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2667| Block 1
# 2667| r2667_1(glval<int>) = VariableAddress[intBuffer] :
# 2667| r2667_2(int) = Constant[8] :
# 2667| m2667_3(int) = Store[intBuffer] : &:r2667_1, r2667_2
# 2668| r2668_1(glval<int>) = VariableAddress[intBuffer] :
# 2668| r2668_2(int *) = CopyValue : r2668_1
# 2668| r2668_3(glval<int *>) = VariableAddress[data] :
# 2668| m2668_4(int *) = Store[data] : &:r2668_3, r2668_2
#-----| Goto -> Block 2
# 2670| Block 2
# 2670| m2670_1(int) = Phi : from 1:m2667_3
# 2670| m2670_2(int *) = Phi : from 0:m2665_3, from 1:m2668_4
# 2670| r2670_3(glval<unknown>) = FunctionAddress[use_int] :
# 2670| r2670_4(glval<int *>) = VariableAddress[data] :
# 2670| r2670_5(int *) = Load[data] : &:r2670_4, m2670_2
# 2670| r2670_6(int) = Load[?] : &:r2670_5, ~m2670_1
# 2670| v2670_7(void) = Call[use_int] : func:r2670_3, 0:r2670_6
# 2670| m2670_8(unknown) = ^CallSideEffect : ~m2663_4
# 2670| m2670_9(unknown) = Chi : total:m2663_4, partial:m2670_8
# 2671| v2671_1(void) = NoOp :
# 2663| v2663_7(void) = ReturnVoid :
# 2663| v2663_8(void) = AliasedUse : ~m2670_9
# 2663| v2663_9(void) = ExitFunction :
# 2684| void test(bool)
# 2684| Block 0
# 2684| v2684_1(void) = EnterFunction :
# 2684| m2684_2(unknown) = AliasedDefinition :
# 2684| m2684_3(unknown) = InitializeNonLocal :
# 2684| m2684_4(unknown) = Chi : total:m2684_2, partial:m2684_3
# 2684| m2684_5(unknown) = UninitializedGroup[#string2686:22,#string2686:27] :
# 2684| m2684_6(unknown) = Chi : total:m2684_4, partial:m2684_5
# 2684| m2684_7(unknown) = UninitializedGroup[#string2686:22,#string2686:27] :
# 2684| m2684_8(unknown) = Chi : total:m2684_6, partial:m2684_7
# 2684| r2684_9(glval<bool>) = VariableAddress[b] :
# 2684| m2684_10(bool) = InitializeParameter[b] : &:r2684_9
# 2686| r2686_1(glval<unknown>) = FunctionAddress[use] :
# 2686| r2686_2(glval<bool>) = VariableAddress[b] :
# 2686| r2686_3(bool) = Load[b] : &:r2686_2, m2684_10
# 2686| v2686_4(void) = ConditionalBranch : r2686_3
#-----| False -> Block 3
#-----| True -> Block 2
# 2686| Block 1
# 2686| m2686_5(char *) = Phi : from 2:m2686_19, from 3:m2686_23
# 2686| r2686_6(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| r2686_7(char *) = Load[#temp2686:18] : &:r2686_6, m2686_5
# 2686| v2686_8(void) = Call[use] : func:r2686_1, 0:r2686_7
# 2686| m2686_9(unknown) = ^CallSideEffect : ~m2684_8
# 2686| m2686_10(unknown) = Chi : total:m2684_8, partial:m2686_9
# 2686| v2686_11(void) = ^BufferReadSideEffect[0] : &:r2686_7, ~m2686_10
# 2686| r2686_12(glval<unknown>) = FunctionAddress[use] :
# 2686| r2686_13(glval<bool>) = VariableAddress[b] :
# 2686| r2686_14(bool) = Load[b] : &:r2686_13, m2684_10
# 2686| v2686_15(void) = ConditionalBranch : r2686_14
#-----| False -> Block 6
#-----| True -> Block 5
# 2686| Block 2
# 2686| r2686_16(glval<char[1]>) = StringConstant[] :
# 2686| r2686_17(char *) = Convert : r2686_16
# 2686| r2686_18(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| m2686_19(char *) = Store[#temp2686:18] : &:r2686_18, r2686_17
#-----| Goto -> Block 1
# 2686| Block 3
# 2686| r2686_20(glval<char[1]>) = StringConstant[] :
# 2686| r2686_21(char *) = Convert : r2686_20
# 2686| r2686_22(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| m2686_23(char *) = Store[#temp2686:18] : &:r2686_22, r2686_21
#-----| Goto -> Block 1
# 2686| Block 4
# 2686| m2686_24(char *) = Phi : from 5:m2686_36, from 6:m2686_40
# 2686| r2686_25(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| r2686_26(char *) = Load[#temp2686:18] : &:r2686_25, m2686_24
# 2686| v2686_27(void) = Call[use] : func:r2686_12, 0:r2686_26
# 2686| m2686_28(unknown) = ^CallSideEffect : ~m2686_10
# 2686| m2686_29(unknown) = Chi : total:m2686_10, partial:m2686_28
# 2686| v2686_30(void) = ^BufferReadSideEffect[0] : &:r2686_26, ~m2686_29
# 2686| r2686_31(bool) = Constant[0] :
# 2686| v2686_32(void) = ConditionalBranch : r2686_31
#-----| False -> Block 7
#-----| True -> Block 8
# 2686| Block 5
# 2686| r2686_33(glval<char[1]>) = StringConstant[] :
# 2686| r2686_34(char *) = Convert : r2686_33
# 2686| r2686_35(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| m2686_36(char *) = Store[#temp2686:18] : &:r2686_35, r2686_34
#-----| Goto -> Block 4
# 2686| Block 6
# 2686| r2686_37(glval<char[1]>) = StringConstant[] :
# 2686| r2686_38(char *) = Convert : r2686_37
# 2686| r2686_39(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| m2686_40(char *) = Store[#temp2686:18] : &:r2686_39, r2686_38
#-----| Goto -> Block 4
# 2687| Block 7
# 2687| v2687_1(void) = NoOp :
# 2684| v2684_11(void) = ReturnVoid :
# 2684| v2684_12(void) = AliasedUse : ~m2686_29
# 2684| v2684_13(void) = ExitFunction :
# 2684| Block 8
# 2684| v2684_14(void) = Unreached :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -2,6 +2,7 @@ missingOperand
unexpectedOperand
duplicateOperand
missingPhiOperand
| ir.cpp:2670:3:2670:9 | Phi: call to use_int | Instruction 'Phi: call to use_int' is missing an operand for predecessor block 'EnterFunction: phi_with_single_input_at_merge' in function '$@'. | ir.cpp:2663:13:2663:42 | void phi_with_single_input_at_merge(bool) | void phi_with_single_input_at_merge(bool) |
missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary

View File

@@ -2,6 +2,7 @@ missingOperand
unexpectedOperand
duplicateOperand
missingPhiOperand
| ir.cpp:2670:3:2670:9 | Phi: call to use_int | Instruction 'Phi: call to use_int' is missing an operand for predecessor block 'EnterFunction: phi_with_single_input_at_merge' in function '$@'. | ir.cpp:2663:13:2663:42 | void phi_with_single_input_at_merge(bool) | void phi_with_single_input_at_merge(bool) |
missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary

View File

@@ -2556,4 +2556,134 @@ void builtin_bitcast(unsigned long ul) {
double d = __builtin_bit_cast(double, ul);
}
void p_points_to_x_or_y(int a, int b) {
int x;
int y;
int* p;
if (a < b) {
p = &x;
} else {
p = &y;
}
*p = 5;
int z = x;
int w = y;
}
int phi_after_while() {
int r;
int *rP = &r;
while(predicateA()) {
int s = 0;
*rP = s;
rP = &s;
}
return r;
}
// This testcase will loop infinitely if the analysis attempts to propagate
// phi inputs with a non-unknown bit offset.
char *recursive_conditional_call_with_increment(char *d, bool b)
{
if (b) {
d = recursive_conditional_call_with_increment(d, b);
}
d++;
return d;
}
struct Recursive
{
Recursive *next;
};
static Recursive *merge(Recursive *a)
{
Recursive *b;
Recursive **p = &b;
while (predicateA())
{
*p = a;
p = &a->next;
}
return b;
}
void use_const_int(const int*);
void escaping_pointer(bool b)
{
int *data;
int l1, l2;
if (b)
{
data = &l1;
}
else
{
data = &l2;
}
use_const_int(data);
}
using int64_t = long long;
#define NULL ((void *)0)
void *malloc(unsigned long);
void use_const_void_pointer(const void *);
static void needs_chi_for_initialize_groups()
{
if (predicateA())
{
int64_t *data = (int64_t *)malloc(100);
if (data != NULL)
{
data = (int64_t *)malloc(100);
}
use_const_void_pointer(data);
}
else
{
int64_t *data = (int64_t *)malloc(100);
if (data != NULL)
{
data = (int64_t *)malloc(200);
}
use_const_void_pointer(data);
}
}
void use_int(int);
static void phi_with_single_input_at_merge(bool b)
{
int *data = nullptr;
if(b) {
int intBuffer = 8;
data = &intBuffer;
}
use_int(*data);
}
void use(const char *fmt);
#define call_use(format) use(format)
#define twice_call_use(format) \
do \
{ \
call_use(format); \
call_use(format); \
} while (0)
void test(bool b)
{
twice_call_use(b ? "" : "");
}
// semmle-extractor-options: -std=c++20 --clang

View File

@@ -16734,6 +16734,463 @@ ir.cpp:
# 2555| v2555_7(void) = AliasedUse : ~m?
# 2555| v2555_8(void) = ExitFunction :
# 2559| void p_points_to_x_or_y(int, int)
# 2559| Block 0
# 2559| v2559_1(void) = EnterFunction :
# 2559| mu2559_2(unknown) = AliasedDefinition :
# 2559| mu2559_3(unknown) = InitializeNonLocal :
# 2559| r2559_4(glval<int>) = VariableAddress[a] :
# 2559| mu2559_5(int) = InitializeParameter[a] : &:r2559_4
# 2559| r2559_6(glval<int>) = VariableAddress[b] :
# 2559| mu2559_7(int) = InitializeParameter[b] : &:r2559_6
# 2560| r2560_1(glval<int>) = VariableAddress[x] :
# 2560| mu2560_2(int) = Uninitialized[x] : &:r2560_1
# 2561| r2561_1(glval<int>) = VariableAddress[y] :
# 2561| mu2561_2(int) = Uninitialized[y] : &:r2561_1
# 2562| r2562_1(glval<int *>) = VariableAddress[p] :
# 2562| mu2562_2(int *) = Uninitialized[p] : &:r2562_1
# 2563| r2563_1(glval<int>) = VariableAddress[a] :
# 2563| r2563_2(int) = Load[a] : &:r2563_1, ~m?
# 2563| r2563_3(glval<int>) = VariableAddress[b] :
# 2563| r2563_4(int) = Load[b] : &:r2563_3, ~m?
# 2563| r2563_5(bool) = CompareLT : r2563_2, r2563_4
# 2563| v2563_6(void) = ConditionalBranch : r2563_5
#-----| False -> Block 2
#-----| True -> Block 1
# 2564| Block 1
# 2564| r2564_1(glval<int>) = VariableAddress[x] :
# 2564| r2564_2(int *) = CopyValue : r2564_1
# 2564| r2564_3(glval<int *>) = VariableAddress[p] :
# 2564| mu2564_4(int *) = Store[p] : &:r2564_3, r2564_2
#-----| Goto -> Block 3
# 2566| Block 2
# 2566| r2566_1(glval<int>) = VariableAddress[y] :
# 2566| r2566_2(int *) = CopyValue : r2566_1
# 2566| r2566_3(glval<int *>) = VariableAddress[p] :
# 2566| mu2566_4(int *) = Store[p] : &:r2566_3, r2566_2
#-----| Goto -> Block 3
# 2568| Block 3
# 2568| r2568_1(int) = Constant[5] :
# 2568| r2568_2(glval<int *>) = VariableAddress[p] :
# 2568| r2568_3(int *) = Load[p] : &:r2568_2, ~m?
# 2568| r2568_4(glval<int>) = CopyValue : r2568_3
# 2568| mu2568_5(int) = Store[?] : &:r2568_4, r2568_1
# 2569| r2569_1(glval<int>) = VariableAddress[z] :
# 2569| r2569_2(glval<int>) = VariableAddress[x] :
# 2569| r2569_3(int) = Load[x] : &:r2569_2, ~m?
# 2569| mu2569_4(int) = Store[z] : &:r2569_1, r2569_3
# 2570| r2570_1(glval<int>) = VariableAddress[w] :
# 2570| r2570_2(glval<int>) = VariableAddress[y] :
# 2570| r2570_3(int) = Load[y] : &:r2570_2, ~m?
# 2570| mu2570_4(int) = Store[w] : &:r2570_1, r2570_3
# 2571| v2571_1(void) = NoOp :
# 2559| v2559_8(void) = ReturnVoid :
# 2559| v2559_9(void) = AliasedUse : ~m?
# 2559| v2559_10(void) = ExitFunction :
# 2573| int phi_after_while()
# 2573| Block 0
# 2573| v2573_1(void) = EnterFunction :
# 2573| mu2573_2(unknown) = AliasedDefinition :
# 2573| mu2573_3(unknown) = InitializeNonLocal :
# 2574| r2574_1(glval<int>) = VariableAddress[r] :
# 2574| mu2574_2(int) = Uninitialized[r] : &:r2574_1
# 2575| r2575_1(glval<int *>) = VariableAddress[rP] :
# 2575| r2575_2(glval<int>) = VariableAddress[r] :
# 2575| r2575_3(int *) = CopyValue : r2575_2
# 2575| mu2575_4(int *) = Store[rP] : &:r2575_1, r2575_3
#-----| Goto -> Block 1
# 2577| Block 1
# 2577| r2577_1(glval<unknown>) = FunctionAddress[predicateA] :
# 2577| r2577_2(bool) = Call[predicateA] : func:r2577_1
# 2577| mu2577_3(unknown) = ^CallSideEffect : ~m?
# 2577| v2577_4(void) = ConditionalBranch : r2577_2
#-----| False -> Block 3
#-----| True -> Block 2
# 2578| Block 2
# 2578| r2578_1(glval<int>) = VariableAddress[s] :
# 2578| r2578_2(int) = Constant[0] :
# 2578| mu2578_3(int) = Store[s] : &:r2578_1, r2578_2
# 2579| r2579_1(glval<int>) = VariableAddress[s] :
# 2579| r2579_2(int) = Load[s] : &:r2579_1, ~m?
# 2579| r2579_3(glval<int *>) = VariableAddress[rP] :
# 2579| r2579_4(int *) = Load[rP] : &:r2579_3, ~m?
# 2579| r2579_5(glval<int>) = CopyValue : r2579_4
# 2579| mu2579_6(int) = Store[?] : &:r2579_5, r2579_2
# 2580| r2580_1(glval<int>) = VariableAddress[s] :
# 2580| r2580_2(int *) = CopyValue : r2580_1
# 2580| r2580_3(glval<int *>) = VariableAddress[rP] :
# 2580| mu2580_4(int *) = Store[rP] : &:r2580_3, r2580_2
#-----| Goto (back edge) -> Block 1
# 2583| Block 3
# 2583| r2583_1(glval<int>) = VariableAddress[#return] :
# 2583| r2583_2(glval<int>) = VariableAddress[r] :
# 2583| r2583_3(int) = Load[r] : &:r2583_2, ~m?
# 2583| mu2583_4(int) = Store[#return] : &:r2583_1, r2583_3
# 2573| r2573_4(glval<int>) = VariableAddress[#return] :
# 2573| v2573_5(void) = ReturnValue : &:r2573_4, ~m?
# 2573| v2573_6(void) = AliasedUse : ~m?
# 2573| v2573_7(void) = ExitFunction :
# 2588| char* recursive_conditional_call_with_increment(char*, bool)
# 2588| Block 0
# 2588| v2588_1(void) = EnterFunction :
# 2588| mu2588_2(unknown) = AliasedDefinition :
# 2588| mu2588_3(unknown) = InitializeNonLocal :
# 2588| r2588_4(glval<char *>) = VariableAddress[d] :
# 2588| mu2588_5(char *) = InitializeParameter[d] : &:r2588_4
# 2588| r2588_6(char *) = Load[d] : &:r2588_4, ~m?
# 2588| mu2588_7(unknown) = InitializeIndirection[d] : &:r2588_6
# 2588| r2588_8(glval<bool>) = VariableAddress[b] :
# 2588| mu2588_9(bool) = InitializeParameter[b] : &:r2588_8
# 2590| r2590_1(glval<bool>) = VariableAddress[b] :
# 2590| r2590_2(bool) = Load[b] : &:r2590_1, ~m?
# 2590| v2590_3(void) = ConditionalBranch : r2590_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2591| Block 1
# 2591| r2591_1(glval<unknown>) = FunctionAddress[recursive_conditional_call_with_increment] :
# 2591| r2591_2(glval<char *>) = VariableAddress[d] :
# 2591| r2591_3(char *) = Load[d] : &:r2591_2, ~m?
# 2591| r2591_4(glval<bool>) = VariableAddress[b] :
# 2591| r2591_5(bool) = Load[b] : &:r2591_4, ~m?
# 2591| r2591_6(char *) = Call[recursive_conditional_call_with_increment] : func:r2591_1, 0:r2591_3, 1:r2591_5
# 2591| mu2591_7(unknown) = ^CallSideEffect : ~m?
# 2591| v2591_8(void) = ^BufferReadSideEffect[0] : &:r2591_3, ~m?
# 2591| mu2591_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r2591_3
# 2591| r2591_10(glval<char *>) = VariableAddress[d] :
# 2591| mu2591_11(char *) = Store[d] : &:r2591_10, r2591_6
#-----| Goto -> Block 2
# 2593| Block 2
# 2593| r2593_1(glval<char *>) = VariableAddress[d] :
# 2593| r2593_2(char *) = Load[d] : &:r2593_1, ~m?
# 2593| r2593_3(int) = Constant[1] :
# 2593| r2593_4(char *) = PointerAdd[1] : r2593_2, r2593_3
# 2593| mu2593_5(char *) = Store[d] : &:r2593_1, r2593_4
# 2594| r2594_1(glval<char *>) = VariableAddress[#return] :
# 2594| r2594_2(glval<char *>) = VariableAddress[d] :
# 2594| r2594_3(char *) = Load[d] : &:r2594_2, ~m?
# 2594| mu2594_4(char *) = Store[#return] : &:r2594_1, r2594_3
# 2588| v2588_10(void) = ReturnIndirection[d] : &:r2588_6, ~m?
# 2588| r2588_11(glval<char *>) = VariableAddress[#return] :
# 2588| v2588_12(void) = ReturnValue : &:r2588_11, ~m?
# 2588| v2588_13(void) = AliasedUse : ~m?
# 2588| v2588_14(void) = ExitFunction :
# 2602| Recursive* merge(Recursive*)
# 2602| Block 0
# 2602| v2602_1(void) = EnterFunction :
# 2602| mu2602_2(unknown) = AliasedDefinition :
# 2602| mu2602_3(unknown) = InitializeNonLocal :
# 2602| r2602_4(glval<Recursive *>) = VariableAddress[a] :
# 2602| mu2602_5(Recursive *) = InitializeParameter[a] : &:r2602_4
# 2602| r2602_6(Recursive *) = Load[a] : &:r2602_4, ~m?
# 2602| mu2602_7(unknown) = InitializeIndirection[a] : &:r2602_6
# 2604| r2604_1(glval<Recursive *>) = VariableAddress[b] :
# 2604| mu2604_2(Recursive *) = Uninitialized[b] : &:r2604_1
# 2605| r2605_1(glval<Recursive **>) = VariableAddress[p] :
# 2605| r2605_2(glval<Recursive *>) = VariableAddress[b] :
# 2605| r2605_3(Recursive **) = CopyValue : r2605_2
# 2605| mu2605_4(Recursive **) = Store[p] : &:r2605_1, r2605_3
#-----| Goto -> Block 1
# 2607| Block 1
# 2607| r2607_1(glval<unknown>) = FunctionAddress[predicateA] :
# 2607| r2607_2(bool) = Call[predicateA] : func:r2607_1
# 2607| mu2607_3(unknown) = ^CallSideEffect : ~m?
# 2607| v2607_4(void) = ConditionalBranch : r2607_2
#-----| False -> Block 3
#-----| True -> Block 2
# 2609| Block 2
# 2609| r2609_1(glval<Recursive *>) = VariableAddress[a] :
# 2609| r2609_2(Recursive *) = Load[a] : &:r2609_1, ~m?
# 2609| r2609_3(glval<Recursive **>) = VariableAddress[p] :
# 2609| r2609_4(Recursive **) = Load[p] : &:r2609_3, ~m?
# 2609| r2609_5(glval<Recursive *>) = CopyValue : r2609_4
# 2609| mu2609_6(Recursive *) = Store[?] : &:r2609_5, r2609_2
# 2610| r2610_1(glval<Recursive *>) = VariableAddress[a] :
# 2610| r2610_2(Recursive *) = Load[a] : &:r2610_1, ~m?
# 2610| r2610_3(glval<Recursive *>) = FieldAddress[next] : r2610_2
# 2610| r2610_4(Recursive **) = CopyValue : r2610_3
# 2610| r2610_5(glval<Recursive **>) = VariableAddress[p] :
# 2610| mu2610_6(Recursive **) = Store[p] : &:r2610_5, r2610_4
#-----| Goto (back edge) -> Block 1
# 2613| Block 3
# 2613| r2613_1(glval<Recursive *>) = VariableAddress[#return] :
# 2613| r2613_2(glval<Recursive *>) = VariableAddress[b] :
# 2613| r2613_3(Recursive *) = Load[b] : &:r2613_2, ~m?
# 2613| mu2613_4(Recursive *) = Store[#return] : &:r2613_1, r2613_3
# 2602| v2602_8(void) = ReturnIndirection[a] : &:r2602_6, ~m?
# 2602| r2602_9(glval<Recursive *>) = VariableAddress[#return] :
# 2602| v2602_10(void) = ReturnValue : &:r2602_9, ~m?
# 2602| v2602_11(void) = AliasedUse : ~m?
# 2602| v2602_12(void) = ExitFunction :
# 2618| void escaping_pointer(bool)
# 2618| Block 0
# 2618| v2618_1(void) = EnterFunction :
# 2618| mu2618_2(unknown) = AliasedDefinition :
# 2618| mu2618_3(unknown) = InitializeNonLocal :
# 2618| r2618_4(glval<bool>) = VariableAddress[b] :
# 2618| mu2618_5(bool) = InitializeParameter[b] : &:r2618_4
# 2620| r2620_1(glval<int *>) = VariableAddress[data] :
# 2620| mu2620_2(int *) = Uninitialized[data] : &:r2620_1
# 2621| r2621_1(glval<int>) = VariableAddress[l1] :
# 2621| mu2621_2(int) = Uninitialized[l1] : &:r2621_1
# 2621| r2621_3(glval<int>) = VariableAddress[l2] :
# 2621| mu2621_4(int) = Uninitialized[l2] : &:r2621_3
# 2622| r2622_1(glval<bool>) = VariableAddress[b] :
# 2622| r2622_2(bool) = Load[b] : &:r2622_1, ~m?
# 2622| v2622_3(void) = ConditionalBranch : r2622_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2624| Block 1
# 2624| r2624_1(glval<int>) = VariableAddress[l1] :
# 2624| r2624_2(int *) = CopyValue : r2624_1
# 2624| r2624_3(glval<int *>) = VariableAddress[data] :
# 2624| mu2624_4(int *) = Store[data] : &:r2624_3, r2624_2
#-----| Goto -> Block 3
# 2628| Block 2
# 2628| r2628_1(glval<int>) = VariableAddress[l2] :
# 2628| r2628_2(int *) = CopyValue : r2628_1
# 2628| r2628_3(glval<int *>) = VariableAddress[data] :
# 2628| mu2628_4(int *) = Store[data] : &:r2628_3, r2628_2
#-----| Goto -> Block 3
# 2630| Block 3
# 2630| r2630_1(glval<unknown>) = FunctionAddress[use_const_int] :
# 2630| r2630_2(glval<int *>) = VariableAddress[data] :
# 2630| r2630_3(int *) = Load[data] : &:r2630_2, ~m?
# 2630| r2630_4(int *) = Convert : r2630_3
# 2630| v2630_5(void) = Call[use_const_int] : func:r2630_1, 0:r2630_4
# 2630| mu2630_6(unknown) = ^CallSideEffect : ~m?
# 2630| v2630_7(void) = ^BufferReadSideEffect[0] : &:r2630_4, ~m?
# 2631| v2631_1(void) = NoOp :
# 2618| v2618_6(void) = ReturnVoid :
# 2618| v2618_7(void) = AliasedUse : ~m?
# 2618| v2618_8(void) = ExitFunction :
# 2639| void needs_chi_for_initialize_groups()
# 2639| Block 0
# 2639| v2639_1(void) = EnterFunction :
# 2639| mu2639_2(unknown) = AliasedDefinition :
# 2639| mu2639_3(unknown) = InitializeNonLocal :
# 2641| r2641_1(glval<unknown>) = FunctionAddress[predicateA] :
# 2641| r2641_2(bool) = Call[predicateA] : func:r2641_1
# 2641| mu2641_3(unknown) = ^CallSideEffect : ~m?
# 2641| v2641_4(void) = ConditionalBranch : r2641_2
#-----| False -> Block 4
#-----| True -> Block 1
# 2643| Block 1
# 2643| r2643_1(glval<long long *>) = VariableAddress[data] :
# 2643| r2643_2(glval<unknown>) = FunctionAddress[malloc] :
# 2643| r2643_3(unsigned long) = Constant[100] :
# 2643| r2643_4(void *) = Call[malloc] : func:r2643_2, 0:r2643_3
# 2643| mu2643_5(unknown) = ^CallSideEffect : ~m?
# 2643| mu2643_6(unknown) = ^InitializeDynamicAllocation : &:r2643_4
# 2643| r2643_7(long long *) = Convert : r2643_4
# 2643| mu2643_8(long long *) = Store[data] : &:r2643_1, r2643_7
# 2644| r2644_1(glval<long long *>) = VariableAddress[data] :
# 2644| r2644_2(long long *) = Load[data] : &:r2644_1, ~m?
# 2644| r2644_3(void *) = Convert : r2644_2
# 2644| r2644_4(void *) = Constant[0] :
# 2644| r2644_5(bool) = CompareNE : r2644_3, r2644_4
# 2644| v2644_6(void) = ConditionalBranch : r2644_5
#-----| False -> Block 3
#-----| True -> Block 2
# 2646| Block 2
# 2646| r2646_1(glval<unknown>) = FunctionAddress[malloc] :
# 2646| r2646_2(unsigned long) = Constant[100] :
# 2646| r2646_3(void *) = Call[malloc] : func:r2646_1, 0:r2646_2
# 2646| mu2646_4(unknown) = ^CallSideEffect : ~m?
# 2646| mu2646_5(unknown) = ^InitializeDynamicAllocation : &:r2646_3
# 2646| r2646_6(long long *) = Convert : r2646_3
# 2646| r2646_7(glval<long long *>) = VariableAddress[data] :
# 2646| mu2646_8(long long *) = Store[data] : &:r2646_7, r2646_6
#-----| Goto -> Block 3
# 2648| Block 3
# 2648| r2648_1(glval<unknown>) = FunctionAddress[use_const_void_pointer] :
# 2648| r2648_2(glval<long long *>) = VariableAddress[data] :
# 2648| r2648_3(long long *) = Load[data] : &:r2648_2, ~m?
# 2648| r2648_4(void *) = Convert : r2648_3
# 2648| v2648_5(void) = Call[use_const_void_pointer] : func:r2648_1, 0:r2648_4
# 2648| mu2648_6(unknown) = ^CallSideEffect : ~m?
# 2648| v2648_7(void) = ^BufferReadSideEffect[0] : &:r2648_4, ~m?
#-----| Goto -> Block 7
# 2652| Block 4
# 2652| r2652_1(glval<long long *>) = VariableAddress[data] :
# 2652| r2652_2(glval<unknown>) = FunctionAddress[malloc] :
# 2652| r2652_3(unsigned long) = Constant[100] :
# 2652| r2652_4(void *) = Call[malloc] : func:r2652_2, 0:r2652_3
# 2652| mu2652_5(unknown) = ^CallSideEffect : ~m?
# 2652| mu2652_6(unknown) = ^InitializeDynamicAllocation : &:r2652_4
# 2652| r2652_7(long long *) = Convert : r2652_4
# 2652| mu2652_8(long long *) = Store[data] : &:r2652_1, r2652_7
# 2653| r2653_1(glval<long long *>) = VariableAddress[data] :
# 2653| r2653_2(long long *) = Load[data] : &:r2653_1, ~m?
# 2653| r2653_3(void *) = Convert : r2653_2
# 2653| r2653_4(void *) = Constant[0] :
# 2653| r2653_5(bool) = CompareNE : r2653_3, r2653_4
# 2653| v2653_6(void) = ConditionalBranch : r2653_5
#-----| False -> Block 6
#-----| True -> Block 5
# 2655| Block 5
# 2655| r2655_1(glval<unknown>) = FunctionAddress[malloc] :
# 2655| r2655_2(unsigned long) = Constant[200] :
# 2655| r2655_3(void *) = Call[malloc] : func:r2655_1, 0:r2655_2
# 2655| mu2655_4(unknown) = ^CallSideEffect : ~m?
# 2655| mu2655_5(unknown) = ^InitializeDynamicAllocation : &:r2655_3
# 2655| r2655_6(long long *) = Convert : r2655_3
# 2655| r2655_7(glval<long long *>) = VariableAddress[data] :
# 2655| mu2655_8(long long *) = Store[data] : &:r2655_7, r2655_6
#-----| Goto -> Block 6
# 2657| Block 6
# 2657| r2657_1(glval<unknown>) = FunctionAddress[use_const_void_pointer] :
# 2657| r2657_2(glval<long long *>) = VariableAddress[data] :
# 2657| r2657_3(long long *) = Load[data] : &:r2657_2, ~m?
# 2657| r2657_4(void *) = Convert : r2657_3
# 2657| v2657_5(void) = Call[use_const_void_pointer] : func:r2657_1, 0:r2657_4
# 2657| mu2657_6(unknown) = ^CallSideEffect : ~m?
# 2657| v2657_7(void) = ^BufferReadSideEffect[0] : &:r2657_4, ~m?
#-----| Goto -> Block 7
# 2659| Block 7
# 2659| v2659_1(void) = NoOp :
# 2639| v2639_4(void) = ReturnVoid :
# 2639| v2639_5(void) = AliasedUse : ~m?
# 2639| v2639_6(void) = ExitFunction :
# 2663| void phi_with_single_input_at_merge(bool)
# 2663| Block 0
# 2663| v2663_1(void) = EnterFunction :
# 2663| mu2663_2(unknown) = AliasedDefinition :
# 2663| mu2663_3(unknown) = InitializeNonLocal :
# 2663| r2663_4(glval<bool>) = VariableAddress[b] :
# 2663| mu2663_5(bool) = InitializeParameter[b] : &:r2663_4
# 2665| r2665_1(glval<int *>) = VariableAddress[data] :
# 2665| r2665_2(int *) = Constant[0] :
# 2665| mu2665_3(int *) = Store[data] : &:r2665_1, r2665_2
# 2666| r2666_1(glval<bool>) = VariableAddress[b] :
# 2666| r2666_2(bool) = Load[b] : &:r2666_1, ~m?
# 2666| v2666_3(void) = ConditionalBranch : r2666_2
#-----| False -> Block 2
#-----| True -> Block 1
# 2667| Block 1
# 2667| r2667_1(glval<int>) = VariableAddress[intBuffer] :
# 2667| r2667_2(int) = Constant[8] :
# 2667| mu2667_3(int) = Store[intBuffer] : &:r2667_1, r2667_2
# 2668| r2668_1(glval<int>) = VariableAddress[intBuffer] :
# 2668| r2668_2(int *) = CopyValue : r2668_1
# 2668| r2668_3(glval<int *>) = VariableAddress[data] :
# 2668| mu2668_4(int *) = Store[data] : &:r2668_3, r2668_2
#-----| Goto -> Block 2
# 2670| Block 2
# 2670| r2670_1(glval<unknown>) = FunctionAddress[use_int] :
# 2670| r2670_2(glval<int *>) = VariableAddress[data] :
# 2670| r2670_3(int *) = Load[data] : &:r2670_2, ~m?
# 2670| r2670_4(int) = Load[?] : &:r2670_3, ~m?
# 2670| v2670_5(void) = Call[use_int] : func:r2670_1, 0:r2670_4
# 2670| mu2670_6(unknown) = ^CallSideEffect : ~m?
# 2671| v2671_1(void) = NoOp :
# 2663| v2663_6(void) = ReturnVoid :
# 2663| v2663_7(void) = AliasedUse : ~m?
# 2663| v2663_8(void) = ExitFunction :
# 2684| void test(bool)
# 2684| Block 0
# 2684| v2684_1(void) = EnterFunction :
# 2684| mu2684_2(unknown) = AliasedDefinition :
# 2684| mu2684_3(unknown) = InitializeNonLocal :
# 2684| r2684_4(glval<bool>) = VariableAddress[b] :
# 2684| mu2684_5(bool) = InitializeParameter[b] : &:r2684_4
#-----| Goto -> Block 1
# 2686| Block 1
# 2686| r2686_1(glval<unknown>) = FunctionAddress[use] :
# 2686| r2686_2(glval<bool>) = VariableAddress[b] :
# 2686| r2686_3(bool) = Load[b] : &:r2686_2, ~m?
# 2686| v2686_4(void) = ConditionalBranch : r2686_3
#-----| False -> Block 4
#-----| True -> Block 3
# 2686| Block 2
# 2686| r2686_5(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| r2686_6(char *) = Load[#temp2686:18] : &:r2686_5, ~m?
# 2686| v2686_7(void) = Call[use] : func:r2686_1, 0:r2686_6
# 2686| mu2686_8(unknown) = ^CallSideEffect : ~m?
# 2686| v2686_9(void) = ^BufferReadSideEffect[0] : &:r2686_6, ~m?
# 2686| r2686_10(glval<unknown>) = FunctionAddress[use] :
# 2686| r2686_11(glval<bool>) = VariableAddress[b] :
# 2686| r2686_12(bool) = Load[b] : &:r2686_11, ~m?
# 2686| v2686_13(void) = ConditionalBranch : r2686_12
#-----| False -> Block 7
#-----| True -> Block 6
# 2686| Block 3
# 2686| r2686_14(glval<char[1]>) = StringConstant[] :
# 2686| r2686_15(char *) = Convert : r2686_14
# 2686| r2686_16(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| mu2686_17(char *) = Store[#temp2686:18] : &:r2686_16, r2686_15
#-----| Goto -> Block 2
# 2686| Block 4
# 2686| r2686_18(glval<char[1]>) = StringConstant[] :
# 2686| r2686_19(char *) = Convert : r2686_18
# 2686| r2686_20(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| mu2686_21(char *) = Store[#temp2686:18] : &:r2686_20, r2686_19
#-----| Goto -> Block 2
# 2686| Block 5
# 2686| r2686_22(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| r2686_23(char *) = Load[#temp2686:18] : &:r2686_22, ~m?
# 2686| v2686_24(void) = Call[use] : func:r2686_10, 0:r2686_23
# 2686| mu2686_25(unknown) = ^CallSideEffect : ~m?
# 2686| v2686_26(void) = ^BufferReadSideEffect[0] : &:r2686_23, ~m?
# 2686| r2686_27(bool) = Constant[0] :
# 2686| v2686_28(void) = ConditionalBranch : r2686_27
#-----| False -> Block 8
#-----| True (back edge) -> Block 1
# 2686| Block 6
# 2686| r2686_29(glval<char[1]>) = StringConstant[] :
# 2686| r2686_30(char *) = Convert : r2686_29
# 2686| r2686_31(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| mu2686_32(char *) = Store[#temp2686:18] : &:r2686_31, r2686_30
#-----| Goto -> Block 5
# 2686| Block 7
# 2686| r2686_33(glval<char[1]>) = StringConstant[] :
# 2686| r2686_34(char *) = Convert : r2686_33
# 2686| r2686_35(glval<char *>) = VariableAddress[#temp2686:18] :
# 2686| mu2686_36(char *) = Store[#temp2686:18] : &:r2686_35, r2686_34
#-----| Goto -> Block 5
# 2687| Block 8
# 2687| v2687_1(void) = NoOp :
# 2684| v2684_6(void) = ReturnVoid :
# 2684| v2684_7(void) = AliasedUse : ~m?
# 2684| v2684_8(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -1,2 +1 @@
testFailures
failures
ERROR: getAllocation() cannot be resolved for type SimpleSSA::MemoryLocation (points_to.ql:31,42-55)

View File

@@ -56,7 +56,7 @@ module UnaliasedSsa {
not memLocation.getVirtualVariable() instanceof AliasedVirtualVariable and
not memLocation instanceof AllNonLocalMemory and
tag = "ussa" and
not ignoreAllocation(memLocation.getAllocation().getAllocationString()) and
not ignoreAllocation(memLocation.getAnAllocation().getAllocationString()) and
value = memLocation.toString() and
element = instr.toString() and
location = instr.getLocation() and

View File

@@ -381,7 +381,7 @@ ssa.cpp:
#-----| Goto -> Block 1
# 69| Block 1
# 69| m69_1(unknown) = Phi : from 0:~m68_4, from 2:~m70_10
# 69| m69_1(unknown) = Phi : from 0:m68_10, from 2:m70_10
# 69| m69_2(char *) = Phi : from 0:m68_8, from 2:m70_6
# 69| m69_3(int) = Phi : from 0:m68_6, from 2:m69_8
# 69| r69_4(glval<int>) = VariableAddress[n] :
@@ -411,9 +411,9 @@ ssa.cpp:
# 71| Block 3
# 71| v71_1(void) = NoOp :
# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10
# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m69_1
# 68| v68_12(void) = ReturnVoid :
# 68| v68_13(void) = AliasedUse : ~m69_1
# 68| v68_13(void) = AliasedUse : m68_3
# 68| v68_14(void) = ExitFunction :
# 75| void ScalarPhi(bool)

View File

@@ -381,7 +381,7 @@ ssa.cpp:
#-----| Goto -> Block 1
# 69| Block 1
# 69| m69_1(unknown) = Phi : from 0:~m68_4, from 2:~m70_10
# 69| m69_1(unknown) = Phi : from 0:m68_10, from 2:m70_10
# 69| m69_2(char *) = Phi : from 0:m68_8, from 2:m70_6
# 69| m69_3(int) = Phi : from 0:m68_6, from 2:m69_8
# 69| r69_4(glval<int>) = VariableAddress[n] :
@@ -411,9 +411,9 @@ ssa.cpp:
# 71| Block 3
# 71| v71_1(void) = NoOp :
# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10
# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m69_1
# 68| v68_12(void) = ReturnVoid :
# 68| v68_13(void) = AliasedUse : ~m69_1
# 68| v68_13(void) = AliasedUse : m68_3
# 68| v68_14(void) = ExitFunction :
# 75| void ScalarPhi(bool)

View File

@@ -468,7 +468,7 @@ test.cpp:
# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_3(char *) = Load[ptr] : &:r56_2, m56_1
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_4(char) = Load[?] : &:r56_3, ~m49_4
# 56| r56_4(char) = Load[?] : &:r56_3, ~m49_12
# 56| valnum = r56_14, r56_4, r59_3
# 56| r56_5(int) = Convert : r56_4
# 56| valnum = r56_15, r56_5, r59_4
@@ -491,7 +491,7 @@ test.cpp:
# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_13(char *) = Load[ptr] : &:r56_12, m56_1
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_14(char) = Load[?] : &:r56_13, ~m49_4
# 56| r56_14(char) = Load[?] : &:r56_13, ~m49_12
# 56| valnum = r56_14, r56_4, r59_3
# 56| r56_15(int) = Convert : r56_14
# 56| valnum = r56_15, r56_5, r59_4
@@ -521,7 +521,7 @@ test.cpp:
# 59| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 59| r59_2(char *) = Load[ptr] : &:r59_1, m56_1
# 59| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 59| r59_3(char) = Load[?] : &:r59_2, ~m49_4
# 59| r59_3(char) = Load[?] : &:r59_2, ~m49_12
# 59| valnum = r56_14, r56_4, r59_3
# 59| r59_4(int) = Convert : r59_3
# 59| valnum = r56_15, r56_5, r59_4

View File

@@ -13,7 +13,6 @@ nodes
| test.cpp:458:6:458:6 | definition of x | semmle.label | definition of x |
| test.cpp:464:6:464:6 | definition of x | semmle.label | definition of x |
| test.cpp:471:6:471:6 | definition of x | semmle.label | definition of x |
| test.cpp:557:15:557:15 | definition of r | semmle.label | definition of r |
#select
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
@@ -28,4 +27,3 @@ nodes
| test.cpp:460:7:460:7 | x | test.cpp:458:6:458:6 | definition of x | test.cpp:458:6:458:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:458:6:458:6 | x | x |
| test.cpp:467:2:467:2 | x | test.cpp:464:6:464:6 | definition of x | test.cpp:464:6:464:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:464:6:464:6 | x | x |
| test.cpp:474:7:474:7 | x | test.cpp:471:6:471:6 | definition of x | test.cpp:471:6:471:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:471:6:471:6 | x | x |
| test.cpp:567:7:567:7 | r | test.cpp:557:15:557:15 | definition of r | test.cpp:557:15:557:15 | definition of r | The variable $@ may not be initialized at this access. | test.cpp:557:15:557:15 | r | r |

View File

@@ -564,5 +564,5 @@ void test45() {
}
*rP = NULL;
use(r); // GOOD [FALSE POSITIVE]
use(r); // GOOD
}