@@ -43,24 +43,82 @@ private module Cached {
4343 class TStageInstruction =
4444 TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction ;
4545
46+ /**
47+ * If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
48+ * this predicate returns the `PhiInputOperand` corresponding to that predecessor block.
49+ * Otherwise, this predicate does not hold.
50+ */
51+ private OldIR:: PhiInputOperand getDegeneratePhiOperand ( OldInstruction oldInstruction ) {
52+ result =
53+ unique( OldIR:: PhiInputOperand operand |
54+ operand = oldInstruction .( OldIR:: PhiInstruction ) .getAnInputOperand ( ) and
55+ operand .getPredecessorBlock ( ) instanceof OldBlock
56+ )
57+ }
58+
4659 cached
4760 predicate hasInstruction ( TStageInstruction instr ) {
4861 instr instanceof TRawInstruction and instr instanceof OldInstruction
4962 or
50- instr instanceof TPhiInstruction
63+ instr = phiInstruction ( _, _)
64+ or
65+ instr = reusedPhiInstruction ( _) and
66+ // Check that the phi instruction is *not* degenerate, but we can't use
67+ // getDegeneratePhiOperand in the first stage with phi instyructions
68+ exists ( OldIR:: PhiInputOperand operand1 , OldIR:: PhiInputOperand operand2 , OldInstruction oldInstruction |
69+ oldInstruction = instr and
70+ operand1 = oldInstruction .( OldIR:: PhiInstruction ) .getAnInputOperand ( ) and
71+ operand1 .getPredecessorBlock ( ) instanceof OldBlock and
72+ operand2 = oldInstruction .( OldIR:: PhiInstruction ) .getAnInputOperand ( ) and
73+ operand2 .getPredecessorBlock ( ) instanceof OldBlock and
74+ operand1 != operand2
75+ )
5176 or
5277 instr instanceof TChiInstruction
5378 or
5479 instr instanceof TUnreachedInstruction
5580 }
5681
57- private IRBlock getNewBlock ( OldBlock oldBlock ) {
58- result .getFirstInstruction ( ) = getNewInstruction ( oldBlock .getFirstInstruction ( ) )
82+ cached IRBlock getNewBlock ( OldBlock oldBlock ) {
83+ exists ( Instruction newEnd , OldIR:: Instruction oldEnd |
84+ (
85+ result .getLastInstruction ( ) = newEnd and
86+ not newEnd instanceof ChiInstruction
87+ or
88+ newEnd = result .getLastInstruction ( ) .( ChiInstruction ) .getAPredecessor ( ) // does this work?
89+ ) and
90+ (
91+ oldBlock .getLastInstruction ( ) = oldEnd and
92+ not oldEnd instanceof OldIR:: ChiInstruction
93+ or
94+ oldEnd = oldBlock .getLastInstruction ( ) .( OldIR:: ChiInstruction ) .getAPredecessor ( ) // does this work?
95+ ) and
96+ oldEnd = getNewInstruction ( newEnd )
97+ )
98+ }
99+
100+ /**
101+ * Gets the block from the old IR that corresponds to `newBlock`.
102+ */
103+ private OldBlock getOldBlock ( IRBlock newBlock ) { getNewBlock ( result ) = newBlock }
104+
105+ /**
106+ * Holds if this iteration of SSA can model the def/use information for the result of
107+ * `oldInstruction`, either because alias analysis has determined a memory location for that
108+ * result, or because a previous iteration of the IR already computed that def/use information
109+ * completely.
110+ */
111+ private predicate canModelResultForOldInstruction ( OldInstruction oldInstruction ) {
112+ // We're modeling the result's memory location ourselves.
113+ exists ( Alias:: getResultMemoryLocation ( oldInstruction ) )
114+ or
115+ // This result was already modeled by a previous iteration of SSA.
116+ Alias:: canReuseSSAForOldResult ( oldInstruction )
59117 }
60118
61119 cached
62120 predicate hasModeledMemoryResult ( Instruction instruction ) {
63- exists ( Alias :: getResultMemoryLocation ( getOldInstruction ( instruction ) ) ) or
121+ canModelResultForOldInstruction ( getOldInstruction ( instruction ) ) or
64122 instruction instanceof PhiInstruction or // Phis always have modeled results
65123 instruction instanceof ChiInstruction // Chis always have modeled results
66124 }
@@ -117,6 +175,30 @@ private module Cached {
117175 )
118176 }
119177
178+ /**
179+ * Gets the new definition instruction for `oldOperand` based on `oldOperand`'s definition in the
180+ * old IR. Usually, this will just get the old definition of `oldOperand` and map it to the
181+ * corresponding new instruction. However, if the old definition of `oldOperand` is a `Phi`
182+ * instruction that is now degenerate due all but one of its predecessor branches being
183+ * unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the
184+ * true definition.
185+ */
186+ private Instruction getNewDefinitionFromOldSSA ( OldIR:: MemoryOperand oldOperand , Overlap overlap ) {
187+ exists ( Overlap originalOverlap |
188+ originalOverlap = oldOperand .getDefinitionOverlap ( ) and
189+ (
190+ result = getNewInstruction ( oldOperand .getAnyDef ( ) ) and
191+ overlap = originalOverlap
192+ or
193+ exists ( OldIR:: PhiInputOperand phiOperand , Overlap phiOperandOverlap |
194+ phiOperand = getDegeneratePhiOperand ( oldOperand .getAnyDef ( ) ) and
195+ result = getNewDefinitionFromOldSSA ( phiOperand , phiOperandOverlap ) and
196+ overlap = combineOverlap ( phiOperandOverlap , originalOverlap )
197+ )
198+ )
199+ )
200+ }
201+
120202 cached
121203 private Instruction getMemoryOperandDefinition0 (
122204 Instruction instruction , MemoryOperandTag tag , Overlap overlap
@@ -148,6 +230,12 @@ private module Cached {
148230 overlap instanceof MustExactlyOverlap and
149231 exists ( MustTotallyOverlap o | exists ( getMemoryOperandDefinition0 ( instruction , tag , o ) ) )
150232 )
233+ or
234+ exists ( OldIR:: NonPhiMemoryOperand oldOperand |
235+ result = getNewDefinitionFromOldSSA ( oldOperand , overlap ) and
236+ oldOperand .getUse ( ) = instruction and
237+ tag = oldOperand .getOperandTag ( )
238+ )
151239 }
152240
153241 /**
@@ -214,10 +302,24 @@ private module Cached {
214302 )
215303 }
216304
305+ /**
306+ * Gets the new definition instruction for the operand of `instr` that flows from the block
307+ * `newPredecessorBlock`, based on that operand's definition in the old IR.
308+ */
309+ private Instruction getNewPhiOperandDefinitionFromOldSSA (
310+ Instruction instr , IRBlock newPredecessorBlock , Overlap overlap
311+ ) {
312+ exists ( OldIR:: PhiInstruction oldPhi , OldIR:: PhiInputOperand oldOperand |
313+ oldPhi = getOldInstruction ( instr ) and
314+ oldOperand = oldPhi .getInputOperand ( getOldBlock ( newPredecessorBlock ) ) and
315+ result = getNewDefinitionFromOldSSA ( oldOperand , overlap )
316+ )
317+ }
318+
217319 pragma [ noopt]
218320 cached
219321 Instruction getPhiOperandDefinition (
220- PhiInstruction instr , IRBlock newPredecessorBlock , Overlap overlap
322+ Instruction instr , IRBlock newPredecessorBlock , Overlap overlap
221323 ) {
222324 exists (
223325 Alias:: MemoryLocation defLocation , Alias:: MemoryLocation useLocation , OldBlock phiBlock ,
@@ -229,6 +331,8 @@ private module Cached {
229331 result = getDefinitionOrChiInstruction ( defBlock , defOffset , defLocation , actualDefLocation ) and
230332 overlap = Alias:: getOverlap ( actualDefLocation , useLocation )
231333 )
334+ or
335+ result = getNewPhiOperandDefinitionFromOldSSA ( instr , newPredecessorBlock , overlap )
232336 }
233337
234338 cached
@@ -249,7 +353,12 @@ private module Cached {
249353 cached
250354 Instruction getPhiInstructionBlockStart ( PhiInstruction instr ) {
251355 exists ( OldBlock oldBlock |
252- instr = getPhi ( oldBlock , _) and
356+ (
357+ instr = getPhi ( oldBlock , _)
358+ or
359+ // Any `Phi` that we propagated from the previous iteration stays in the same block.
360+ getOldInstruction ( instr ) .getBlock ( ) = oldBlock
361+ ) and
253362 result = getNewInstruction ( oldBlock .getFirstInstruction ( ) )
254363 )
255364 }
@@ -335,6 +444,9 @@ private module Cached {
335444 result = vvar .getType ( )
336445 )
337446 or
447+ instr = reusedPhiInstruction ( _) and
448+ result = instr .( OldInstruction ) .getResultLanguageType ( )
449+ or
338450 instr = unreachedInstruction ( _) and result = Language:: getVoidType ( )
339451 }
340452
0 commit comments