@@ -15,6 +15,43 @@ private class OldInstruction = Reachability::ReachableInstruction;
1515
1616import Cached
1717
18+ /**
19+ * Holds if `instruction` is the first instruction that may be followed by
20+ * an `InitializeGroup` instruction, and the enclosing function of
21+ * `instruction` is `func`.
22+ */
23+ private predicate isFirstInstructionBeforeInitializeGroup ( Instruction instruction , IRFunction func ) {
24+ instruction = getChi ( any ( OldIR:: InitializeNonLocalInstruction init ) ) and
25+ func = instruction .getEnclosingIRFunction ( )
26+ }
27+
28+ /** Gets the `i`'th `InitializeGroup` instruction in `func`. */
29+ private InitializeGroupInstruction getInitGroupInstruction ( int i , IRFunction func ) {
30+ exists ( Alias:: VariableGroup vg |
31+ vg .getIRFunction ( ) = func and
32+ vg .getInitializationOrder ( ) = i and
33+ result = initializeGroup ( vg )
34+ )
35+ }
36+
37+ /**
38+ * Holds if `instruction` is the last instruction in the chain of `InitializeGroup`
39+ * instructions in `func`. The chain of instructions may be empty in which case
40+ * `instruction` satisfies
41+ * ```
42+ * isFirstInstructionBeforeInitializeGroup(instruction, func)
43+ * ```
44+ */
45+ predicate isLastInstructionForInitializeGroups ( Instruction instruction , IRFunction func ) {
46+ exists ( int i |
47+ instruction = getInitGroupInstruction ( i , func ) and
48+ not exists ( getInitGroupInstruction ( i + 1 , func ) )
49+ )
50+ or
51+ isFirstInstructionBeforeInitializeGroup ( instruction , func ) and
52+ not exists ( getInitGroupInstruction ( 0 , func ) )
53+ }
54+
1855cached
1956private module Cached {
2057 cached
@@ -45,7 +82,8 @@ private module Cached {
4582 }
4683
4784 class TStageInstruction =
48- TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction ;
85+ TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
86+ TInitializeGroupInstruction ;
4987
5088 /**
5189 * If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
@@ -78,6 +116,8 @@ private module Cached {
78116 or
79117 instr instanceof TChiInstruction
80118 or
119+ instr instanceof TInitializeGroupInstruction
120+ or
81121 instr instanceof TUnreachedInstruction
82122 }
83123
@@ -123,7 +163,8 @@ private module Cached {
123163 predicate hasModeledMemoryResult ( Instruction instruction ) {
124164 canModelResultForOldInstruction ( getOldInstruction ( instruction ) ) or
125165 instruction instanceof PhiInstruction or // Phis always have modeled results
126- instruction instanceof ChiInstruction // Chis always have modeled results
166+ instruction instanceof ChiInstruction or // Chis always have modeled results
167+ instruction instanceof InitializeGroupInstruction // Group initializers always have modeled results
127168 }
128169
129170 cached
@@ -143,7 +184,7 @@ private module Cached {
143184 // conflated if it's associated with a conflated location.
144185 exists ( Alias:: MemoryLocation location |
145186 instruction = getPhi ( _, location ) and
146- not exists ( location .getAllocation ( ) )
187+ not exists ( location .getAnAllocation ( ) )
147188 )
148189 }
149190
@@ -264,7 +305,12 @@ private module Cached {
264305 }
265306
266307 cached
267- IRVariable getAnInitializeGroupVariable ( InitializeGroupInstruction instr ) { none ( ) }
308+ IRVariable getAnInitializeGroupVariable ( InitializeGroupInstruction init ) {
309+ exists ( Alias:: VariableGroup vg |
310+ init = initializeGroup ( vg ) and
311+ result = vg .getAnAllocation ( ) .getABaseInstruction ( ) .( VariableInstruction ) .getIRVariable ( )
312+ )
313+ }
268314
269315 /**
270316 * Holds if `instr` is part of a cycle in the operand graph that doesn't go
@@ -347,14 +393,28 @@ private module Cached {
347393 )
348394 }
349395
350- /*
351- * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
352- * that node is its successor in the new successor relation, and the Chi node's successors are
353- * the new instructions generated from the successors of the old instruction
354- */
396+ private InitializeGroupInstruction firstInstructionToInitializeGroup (
397+ Instruction instruction , EdgeKind kind
398+ ) {
399+ exists ( IRFunction func |
400+ isFirstInstructionBeforeInitializeGroup ( instruction , func ) and
401+ result = getInitGroupInstruction ( 0 , func ) and
402+ kind instanceof GotoEdge
403+ )
404+ }
355405
356- cached
357- Instruction getInstructionSuccessor ( Instruction instruction , EdgeKind kind ) {
406+ private Instruction getNextInitializeGroupInstruction ( Instruction instruction , EdgeKind kind ) {
407+ exists ( int i , IRFunction func |
408+ func = instruction .getEnclosingIRFunction ( ) and
409+ instruction = getInitGroupInstruction ( i , func ) and
410+ result = getInitGroupInstruction ( i + 1 , func ) and
411+ kind instanceof GotoEdge
412+ )
413+ }
414+
415+ private Instruction getInstructionSuccessorAfterInitializeGroup0 (
416+ Instruction instruction , EdgeKind kind
417+ ) {
358418 if hasChiNode ( _, getOldInstruction ( instruction ) )
359419 then
360420 result = getChi ( getOldInstruction ( instruction ) ) and
@@ -374,6 +434,35 @@ private module Cached {
374434 )
375435 }
376436
437+ private Instruction getInstructionSuccessorAfterInitializeGroup (
438+ Instruction instruction , EdgeKind kind
439+ ) {
440+ exists ( IRFunction func , Instruction firstBeforeInitializeGroup |
441+ isLastInstructionForInitializeGroups ( instruction , func ) and
442+ isFirstInstructionBeforeInitializeGroup ( firstBeforeInitializeGroup , func ) and
443+ result = getInstructionSuccessorAfterInitializeGroup0 ( firstBeforeInitializeGroup , kind )
444+ )
445+ }
446+
447+ /**
448+ * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
449+ * that node is its successor in the new successor relation, and the Chi node's successors are
450+ * the new instructions generated from the successors of the old instruction.
451+ *
452+ * Furthermore, the entry block is augmented with `InitializeGroup` instructions.
453+ */
454+ cached
455+ Instruction getInstructionSuccessor ( Instruction instruction , EdgeKind kind ) {
456+ result = firstInstructionToInitializeGroup ( instruction , kind )
457+ or
458+ result = getNextInitializeGroupInstruction ( instruction , kind )
459+ or
460+ result = getInstructionSuccessorAfterInitializeGroup ( instruction , kind )
461+ or
462+ not isFirstInstructionBeforeInitializeGroup ( instruction , _) and
463+ result = getInstructionSuccessorAfterInitializeGroup0 ( instruction , kind )
464+ }
465+
377466 cached
378467 Instruction getInstructionBackEdgeSuccessor ( Instruction instruction , EdgeKind kind ) {
379468 exists ( OldInstruction oldInstruction |
@@ -409,6 +498,11 @@ private module Cached {
409498 exists ( IRFunctionBase irFunc |
410499 instr = unreachedInstruction ( irFunc ) and result = irFunc .getFunction ( )
411500 )
501+ or
502+ exists ( Alias:: VariableGroup vg |
503+ instr = initializeGroup ( vg ) and
504+ result = vg .getIRFunction ( ) .getFunction ( )
505+ )
412506 }
413507
414508 cached
@@ -426,6 +520,11 @@ private module Cached {
426520 result = vvar .getType ( )
427521 )
428522 or
523+ exists ( Alias:: VariableGroup vg |
524+ instr = initializeGroup ( vg ) and
525+ result = vg .getType ( )
526+ )
527+ or
429528 instr = reusedPhiInstruction ( _) and
430529 result = instr .( OldInstruction ) .getResultLanguageType ( )
431530 or
@@ -451,6 +550,8 @@ private module Cached {
451550 or
452551 instr = chiInstruction ( _) and opcode instanceof Opcode:: Chi
453552 or
553+ instr = initializeGroup ( _) and opcode instanceof Opcode:: InitializeGroup
554+ or
454555 instr = unreachedInstruction ( _) and opcode instanceof Opcode:: Unreached
455556 }
456557
@@ -467,6 +568,11 @@ private module Cached {
467568 instr = chiInstruction ( primaryInstr ) and result = primaryInstr .getEnclosingIRFunction ( )
468569 )
469570 or
571+ exists ( Alias:: VariableGroup vg |
572+ instr = initializeGroup ( vg ) and
573+ result = vg .getIRFunction ( )
574+ )
575+ or
470576 instr = unreachedInstruction ( result )
471577 }
472578
@@ -671,19 +777,30 @@ private import DefUse
671777 * potentially very sparse.
672778 */
673779module DefUse {
780+ bindingset [ index, block]
781+ pragma [ inline_late]
782+ private int getNonChiOffset ( int index , OldBlock block ) {
783+ exists ( IRFunction func | func = block .getEnclosingIRFunction ( ) |
784+ if getNewBlock ( block ) = func .getEntryBlock ( )
785+ then result = 2 * ( index + count ( VariableGroup vg | vg .getIRFunction ( ) = func ) )
786+ else result = 2 * index
787+ )
788+ }
789+
790+ bindingset [ index, block]
791+ pragma [ inline_late]
792+ private int getChiOffset ( int index , OldBlock block ) { result = getNonChiOffset ( index , block ) + 1 }
793+
674794 /**
675795 * Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
676796 */
677797 Instruction getDefinitionOrChiInstruction (
678798 OldBlock defBlock , int defOffset , Alias:: MemoryLocation defLocation ,
679799 Alias:: MemoryLocation actualDefLocation
680800 ) {
681- exists ( OldInstruction oldInstr , int oldOffset |
682- oldInstr = defBlock .getInstruction ( oldOffset ) and
683- oldOffset >= 0
684- |
801+ exists ( OldInstruction oldInstr , int oldOffset | oldInstr = defBlock .getInstruction ( oldOffset ) |
685802 // An odd offset corresponds to the `Chi` instruction.
686- defOffset = oldOffset * 2 + 1 and
803+ defOffset = getChiOffset ( oldOffset , defBlock ) and
687804 result = getChi ( oldInstr ) and
688805 (
689806 defLocation = Alias:: getResultMemoryLocation ( oldInstr ) or
@@ -692,7 +809,7 @@ module DefUse {
692809 actualDefLocation = defLocation .getVirtualVariable ( )
693810 or
694811 // An even offset corresponds to the original instruction.
695- defOffset = oldOffset * 2 and
812+ defOffset = getNonChiOffset ( oldOffset , defBlock ) and
696813 result = getNewInstruction ( oldInstr ) and
697814 (
698815 defLocation = Alias:: getResultMemoryLocation ( oldInstr ) or
@@ -705,6 +822,26 @@ module DefUse {
705822 hasDefinition ( _, defLocation , defBlock , defOffset ) and
706823 result = getPhi ( defBlock , defLocation ) and
707824 actualDefLocation = defLocation
825+ or
826+ exists (
827+ Alias:: VariableGroup vg , int index , InitializeGroupInstruction initGroup ,
828+ Alias:: GroupedMemoryLocation gml
829+ |
830+ // Add 3 to account for the function prologue:
831+ // v1(void) = EnterFunction
832+ // m1(unknown) = AliasedDefinition
833+ // m2(unknown) = InitializeNonLocal
834+ index = 3 + vg .getInitializationOrder ( ) and
835+ not gml .isMayAccess ( ) and
836+ gml .isSome ( ) and
837+ gml .getGroup ( ) = vg and
838+ vg .getIRFunction ( ) .getEntryBlock ( ) = defBlock and
839+ initGroup = initializeGroup ( vg ) and
840+ ( defLocation = gml or defLocation = gml .getVirtualVariable ( ) ) and
841+ result = initGroup and
842+ defOffset = 2 * index and
843+ actualDefLocation = defLocation
844+ )
708845 }
709846
710847 /**
@@ -845,8 +982,18 @@ module DefUse {
845982 block .getInstruction ( index ) = def and
846983 overlap = Alias:: getOverlap ( defLocation , useLocation ) and
847984 if overlap instanceof MayPartiallyOverlap
848- then offset = ( index * 2 ) + 1 // The use will be connected to the definition on the `Chi` instruction.
849- else offset = index * 2 // The use will be connected to the definition on the original instruction.
985+ then offset = getChiOffset ( index , block ) // The use will be connected to the definition on the `Chi` instruction.
986+ else offset = getNonChiOffset ( index , block ) // The use will be connected to the definition on the original instruction.
987+ )
988+ or
989+ exists ( InitializeGroupInstruction initGroup , int index , VariableGroup vg |
990+ initGroup .getEnclosingIRFunction ( ) .getEntryBlock ( ) = getNewBlock ( block ) and
991+ vg = defLocation .( Alias:: GroupedMemoryLocation ) .getGroup ( ) and
992+ // EnterFunction + AliasedDefinition + InitializeNonLocal + index
993+ index = 3 + vg .getInitializationOrder ( ) and
994+ initGroup = initializeGroup ( vg ) and
995+ exists ( Alias:: getOverlap ( defLocation , useLocation ) ) and
996+ offset = 2 * index
850997 )
851998 }
852999
@@ -907,10 +1054,11 @@ module DefUse {
9071054 block .getInstruction ( index ) = use and
9081055 (
9091056 // A direct use of the location.
910- useLocation = Alias:: getOperandMemoryLocation ( use .getAnOperand ( ) ) and offset = index * 2
1057+ useLocation = Alias:: getOperandMemoryLocation ( use .getAnOperand ( ) ) and
1058+ offset = getNonChiOffset ( index , block )
9111059 or
9121060 // A `Chi` instruction will include a use of the virtual variable.
913- hasChiNode ( useLocation , use ) and offset = ( index * 2 ) + 1
1061+ hasChiNode ( useLocation , use ) and offset = getChiOffset ( index , block )
9141062 )
9151063 )
9161064 }
@@ -1061,4 +1209,6 @@ module Ssa {
10611209 predicate hasChiInstruction = Cached:: hasChiInstructionCached / 1 ;
10621210
10631211 predicate hasUnreachedInstruction = Cached:: hasUnreachedInstructionCached / 1 ;
1212+
1213+ class VariableGroup = Alias:: VariableGroup ;
10641214}
0 commit comments