Predicate Cached::getInstructionSuccessor
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:
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}
.
Import path
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind)