Skip to content

Commit 72b52cc

Browse files
committed
C++: Insert Chi instructions after InitializeGroup instructions whose variable group's virtual variable is all aliased memory.
1 parent d1e1037 commit 72b52cc

File tree

3 files changed

+154
-25
lines changed

3 files changed

+154
-25
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 130 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ private InitializeGroupInstruction getInitGroupInstruction(int i, IRFunction fun
4545
predicate isLastInstructionForInitializeGroups(Instruction instruction, IRFunction func) {
4646
exists(int i |
4747
instruction = getInitGroupInstruction(i, func) and
48+
not exists(getChi(instruction)) and
49+
not exists(getInitGroupInstruction(i + 1, func))
50+
)
51+
or
52+
exists(int i |
53+
instruction = getChi(getInitGroupInstruction(i, func)) and
4854
not exists(getInitGroupInstruction(i + 1, func))
4955
)
5056
or
@@ -69,6 +75,11 @@ private module Cached {
6975
hasChiNode(_, primaryInstruction)
7076
}
7177

78+
cached
79+
predicate hasChiNodeAfterInitializeGroup(InitializeGroupInstruction initGroup) {
80+
hasChiNodeAfterInitializeGroup(_, initGroup)
81+
}
82+
7283
cached
7384
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
7485
exists(OldIR::Instruction oldInstruction |
@@ -175,9 +186,18 @@ private module Cached {
175186
or
176187
// Chi instructions track virtual variables, and therefore a chi instruction is
177188
// conflated if it's associated with the aliased virtual variable.
178-
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
179-
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
189+
exists(Instruction input | instruction = getChi(input) |
190+
instruction = getChi(input) and
191+
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
180192
Alias::AliasedVirtualVariable
193+
or
194+
// A chi following an `InitializeGroupInstruction` only happens when the virtual
195+
// variable of the grouped memory location is `{AllAliasedMemory}`.
196+
exists(Alias::GroupedMemoryLocation gml |
197+
instruction = getChi(input) and
198+
input = initializeGroup(gml.getGroup()) and
199+
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
200+
)
181201
)
182202
or
183203
// Phi instructions track locations, and therefore a phi instruction is
@@ -246,7 +266,11 @@ private module Cached {
246266
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
247267
)
248268
or
249-
instruction = getChi(getOldInstruction(result)) and
269+
(
270+
instruction = getChi(getOldInstruction(result))
271+
or
272+
instruction = getChi(result.(InitializeGroupInstruction))
273+
) and
250274
tag instanceof ChiPartialOperandTag and
251275
overlap instanceof MustExactlyOverlap
252276
or
@@ -365,6 +389,18 @@ private module Cached {
365389
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
366390
}
367391

392+
private ChiInstruction getChiAfterInitializeGroup(int i, IRFunction func) {
393+
result =
394+
rank[i + 1](VariableGroup vg, InitializeGroupInstruction initGroup, ChiInstruction chi, int r |
395+
initGroup.getEnclosingIRFunction() = func and
396+
chi = getChi(initGroup) and
397+
initGroup = initializeGroup(vg) and
398+
r = vg.getInitializationOrder()
399+
|
400+
chi order by r
401+
)
402+
}
403+
368404
cached
369405
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
370406
exists(
@@ -378,6 +414,19 @@ private module Cached {
378414
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
379415
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
380416
)
417+
or
418+
exists(InitializeGroupInstruction initGroup, IRFunction func |
419+
chiInstr = getChi(initGroup) and
420+
func = initGroup.getEnclosingIRFunction()
421+
|
422+
chiInstr = getChiAfterInitializeGroup(0, func) and
423+
isFirstInstructionBeforeInitializeGroup(result, func)
424+
or
425+
exists(int i |
426+
chiInstr = getChiAfterInitializeGroup(i + 1, func) and
427+
result = getChiAfterInitializeGroup(i, func)
428+
)
429+
)
381430
}
382431

383432
cached
@@ -407,8 +456,20 @@ private module Cached {
407456
exists(int i, IRFunction func |
408457
func = instruction.getEnclosingIRFunction() and
409458
instruction = getInitGroupInstruction(i, func) and
410-
result = getInitGroupInstruction(i + 1, func) and
411459
kind instanceof GotoEdge
460+
|
461+
if hasChiNodeAfterInitializeGroup(_, instruction)
462+
then result = getChi(instruction)
463+
else result = getInitGroupInstruction(i + 1, func)
464+
)
465+
or
466+
exists(int i, IRFunction func, InitializeGroupInstruction initGroup |
467+
func = instruction.getEnclosingIRFunction() and
468+
instruction = getChi(initGroup) and
469+
initGroup = getInitGroupInstruction(i, func) and
470+
kind instanceof GotoEdge
471+
|
472+
result = getInitGroupInstruction(i + 1, func)
412473
)
413474
}
414475

@@ -503,6 +564,11 @@ private module Cached {
503564
instr = initializeGroup(vg) and
504565
result = vg.getIRFunction().getFunction()
505566
)
567+
or
568+
exists(InitializeGroupInstruction initGroup |
569+
instr = chiInstruction(initGroup) and
570+
result = getInstructionAst(initGroup)
571+
)
506572
}
507573

508574
cached
@@ -515,9 +581,11 @@ private module Cached {
515581
)
516582
or
517583
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
518-
instr = chiInstruction(primaryInstr) and
519-
hasChiNode(vvar, primaryInstr) and
520-
result = vvar.getType()
584+
instr = chiInstruction(primaryInstr) and result = vvar.getType()
585+
|
586+
hasChiNode(vvar, primaryInstr)
587+
or
588+
hasChiNodeAfterInitializeGroup(vvar, primaryInstr)
521589
)
522590
or
523591
exists(Alias::VariableGroup vg |
@@ -564,7 +632,7 @@ private module Cached {
564632
result = blockStartInstr.getEnclosingIRFunction()
565633
)
566634
or
567-
exists(OldInstruction primaryInstr |
635+
exists(Instruction primaryInstr |
568636
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
569637
)
570638
or
@@ -587,14 +655,16 @@ private module Cached {
587655
instruction = getChi(oldInstruction) and
588656
result = getNewInstruction(oldInstruction)
589657
)
658+
or
659+
instruction = getChi(result.(InitializeGroupInstruction))
590660
}
591661
}
592662

593663
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
594664

595665
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
596666

597-
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
667+
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
598668

599669
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
600670
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
@@ -615,6 +685,16 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
615685
)
616686
}
617687

688+
private predicate hasChiNodeAfterInitializeGroup(
689+
Alias::AliasedVirtualVariable vvar, InitializeGroupInstruction initGroup
690+
) {
691+
exists(Alias::GroupedMemoryLocation defLocation |
692+
initGroup = initializeGroup(defLocation.getGroup()) and
693+
defLocation.getVirtualVariable() = vvar and
694+
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
695+
)
696+
}
697+
618698
private import PhiInsertion
619699

620700
/**
@@ -781,7 +861,10 @@ module DefUse {
781861
pragma[inline_late]
782862
private int getNonChiOffset(int index, OldBlock block) {
783863
exists(IRFunction func | func = block.getEnclosingIRFunction() |
784-
if getNewBlock(block) = func.getEntryBlock()
864+
if
865+
getNewBlock(block) = func.getEntryBlock() and
866+
not block.getInstruction(index) instanceof InitializeNonLocalInstruction and
867+
not block.getInstruction(index) instanceof AliasedDefinitionInstruction
785868
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
786869
else result = 2 * index
787870
)
@@ -794,7 +877,7 @@ module DefUse {
794877
/**
795878
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
796879
*/
797-
Instruction getDefinitionOrChiInstruction(
880+
private Instruction getDefinitionOrChiInstruction0(
798881
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
799882
Alias::MemoryLocation actualDefLocation
800883
) {
@@ -837,10 +920,38 @@ module DefUse {
837920
gml.getGroup() = vg and
838921
vg.getIRFunction().getEntryBlock() = defBlock and
839922
initGroup = initializeGroup(vg) and
840-
(defLocation = gml or defLocation = gml.getVirtualVariable()) and
923+
(defLocation = gml or defLocation = gml.getVirtualVariable())
924+
|
841925
result = initGroup and
842926
defOffset = 2 * index and
843927
actualDefLocation = defLocation
928+
or
929+
result = getChi(initGroup) and
930+
defOffset = 2 * index + 1 and
931+
actualDefLocation = defLocation.getVirtualVariable()
932+
)
933+
}
934+
935+
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
936+
exists(IRFunction func |
937+
isFirstInstructionBeforeInitializeGroup(oldResult, func) and
938+
isLastInstructionForInitializeGroups(result, func)
939+
)
940+
}
941+
942+
Instruction getDefinitionOrChiInstruction(
943+
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
944+
Alias::MemoryLocation actualDefLocation
945+
) {
946+
exists(Instruction oldResult |
947+
oldResult =
948+
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
949+
(
950+
result = remapGetDefinitionOrChiInstruction(oldResult)
951+
or
952+
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
953+
result = oldResult
954+
)
844955
)
845956
}
846957

@@ -986,14 +1097,16 @@ module DefUse {
9861097
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
9871098
)
9881099
or
989-
exists(InitializeGroupInstruction initGroup, int index, VariableGroup vg |
1100+
exists(InitializeGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
9901101
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
9911102
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
9921103
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
9931104
index = 3 + vg.getInitializationOrder() and
9941105
initGroup = initializeGroup(vg) and
995-
exists(Alias::getOverlap(defLocation, useLocation)) and
996-
offset = 2 * index
1106+
overlap = Alias::getOverlap(defLocation, useLocation) and
1107+
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterInitializeGroup(initGroup)
1108+
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
1109+
else offset = 2 * index // The use will be connected to the definition on the original instruction.
9971110
)
9981111
}
9991112

@@ -1208,6 +1321,8 @@ module Ssa {
12081321

12091322
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
12101323

1324+
predicate hasChiNodeAfterInitializeGroup = Cached::hasChiNodeAfterInitializeGroup/1;
1325+
12111326
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
12121327

12131328
class VariableGroup = Alias::VariableGroup;

cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ newtype TInstruction =
4343
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
4444
AliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
4545
} or
46-
TAliasedSsaInitializeGroupInstruction(AliasedSsa::Ssa::VariableGroup vg)
46+
TAliasedSsaInitializeGroupInstruction(AliasedSsa::Ssa::VariableGroup vg) or
47+
TAliasedSsaChiAfterInitializeGroupInstruction(TAliasedSsaInitializeGroupInstruction initGroup) {
48+
AliasedSsa::Ssa::hasChiNodeAfterInitializeGroup(initGroup)
49+
}
4750

4851
/**
4952
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
@@ -64,7 +67,11 @@ module UnaliasedSsaInstructions {
6467

6568
class TChiInstruction = TUnaliasedSsaChiInstruction;
6669

67-
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
70+
class TInitializeGroupInstruction = TUnaliasedSsaInitializeGroupInstruction;
71+
72+
class TRawOrInitializeGroupInstruction = TRawInstruction or TInitializeGroupInstruction;
73+
74+
TChiInstruction chiInstruction(TRawOrInitializeGroupInstruction primaryInstruction) {
6875
result = TUnaliasedSsaChiInstruction(primaryInstruction)
6976
}
7077

@@ -76,10 +83,6 @@ module UnaliasedSsaInstructions {
7683

7784
class VariableGroup = UnaliasedSsa::Ssa::VariableGroup;
7885

79-
class TInitializeGroupInstruction = TUnaliasedSsaInitializeGroupInstruction;
80-
81-
class TRawOrInitializeGroupInstruction = TRawInstruction or TInitializeGroupInstruction;
82-
8386
// This really should just be `TUnaliasedSsaInitializeGroupInstruction`, but that makes the
8487
// compiler realize that certain expressions in `SSAConstruction` are unsatisfiable.
8588
TRawOrInitializeGroupInstruction initializeGroup(VariableGroup vg) { none() }
@@ -104,10 +107,15 @@ module AliasedSsaInstructions {
104107
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
105108
}
106109

107-
class TChiInstruction = TAliasedSsaChiInstruction;
110+
class TChiInstruction =
111+
TAliasedSsaChiInstruction or TAliasedSsaChiAfterInitializeGroupInstruction;
112+
113+
class TRawOrInitialzieGroupInstruction = TRawInstruction or TAliasedSsaInitializeGroupInstruction;
108114

109-
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
115+
TChiInstruction chiInstruction(TRawOrInitialzieGroupInstruction primaryInstruction) {
110116
result = TAliasedSsaChiInstruction(primaryInstruction)
117+
or
118+
result = TAliasedSsaChiAfterInitializeGroupInstruction(primaryInstruction)
111119
}
112120

113121
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;

cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ private import semmle.code.cpp.ir.internal.Overlap
1212
* Provides the newtype used to represent operands across all phases of the IR.
1313
*/
1414
private module Internal {
15+
private class TAliasedChiInstruction =
16+
TAliasedSsaChiInstruction or TAliasedSsaChiAfterInitializeGroupInstruction;
17+
1518
/**
1619
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
1720
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
@@ -52,7 +55,7 @@ private module Internal {
5255
) {
5356
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
5457
} or
55-
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
58+
TAliasedChiOperand(TAliasedChiInstruction useInstr, ChiOperandTag tag) { any() }
5659
}
5760

5861
/**
@@ -198,10 +201,13 @@ module AliasedSsaOperands {
198201
)
199202
}
200203

204+
private class TChiInstruction =
205+
TAliasedSsaChiInstruction or TAliasedSsaChiAfterInitializeGroupInstruction;
206+
201207
/**
202208
* Returns the Chi operand with the specified parameters.
203209
*/
204-
TChiOperand chiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) {
210+
TChiOperand chiOperand(TChiInstruction useInstr, ChiOperandTag tag) {
205211
result = Internal::TAliasedChiOperand(useInstr, tag)
206212
}
207213
}

0 commit comments

Comments
 (0)