@@ -103,8 +103,8 @@ class SsaOptimizerTask extends CompilerTask {
103103
104104 measure (() {
105105 List <OptimizationPhase > phases = [
106- // Run trivial instruction simplification first to optimize
107- // some patterns useful for type conversion.
106+ // Run trivial instruction simplification first to optimize some
107+ // patterns useful for type conversion.
108108 SsaInstructionSimplifier (
109109 globalInferenceResults,
110110 _options,
@@ -113,6 +113,7 @@ class SsaOptimizerTask extends CompilerTask {
113113 registry,
114114 log,
115115 metrics,
116+ beforeTypePropagation: true ,
116117 ),
117118 SsaTypeConversionInserter (closedWorld),
118119 SsaRedundantPhiEliminator (),
@@ -123,8 +124,7 @@ class SsaOptimizerTask extends CompilerTask {
123124 closedWorld,
124125 log,
125126 ),
126- // After type propagation, more instructions can be
127- // simplified.
127+ // After type propagation, more instructions can be simplified.
128128 SsaInstructionSimplifier (
129129 globalInferenceResults,
130130 _options,
@@ -309,6 +309,13 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
309309 final CodegenRegistry _registry;
310310 final OptimizationTestLog ? _log;
311311 final SsaMetrics _metrics;
312+
313+ /// Most simplifications become enabled when the types are refined by type
314+ /// propagation. Some simplifications remove code that helps type progagation
315+ /// produce a better result. These simplifications are inhibited when
316+ /// [beforeTypePropagation] is `true` to ensure they are seeing the propagated
317+ /// types.
318+ final bool beforeTypePropagation;
312319 late final HGraph _graph;
313320
314321 SsaInstructionSimplifier (
@@ -318,8 +325,9 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
318325 this ._typeRecipeDomain,
319326 this ._registry,
320327 this ._log,
321- this ._metrics,
322- );
328+ this ._metrics, {
329+ this .beforeTypePropagation = false ,
330+ });
323331
324332 JCommonElements get commonElements => _closedWorld.commonElements;
325333
@@ -418,8 +426,6 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
418426
419427 // Simplify some CFG diamonds to equivalent expressions.
420428 void simplifyPhis (HBasicBlock block) {
421- if (block.predecessors.length != 2 ) return ;
422-
423429 // Do 'statement' simplifications first, as they might reduce the number of
424430 // phis to one, enabling an 'expression' simplification.
425431 var phi = block.phis.firstPhi;
@@ -429,6 +435,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
429435 phi = next;
430436 }
431437
438+ if (block.predecessors.length != 2 ) return ;
432439 phi = block.phis.firstPhi;
433440 if (phi != null && phi.next == null ) {
434441 simplifyExpressionPhi (block, phi);
@@ -438,6 +445,10 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
438445 /// Simplify a single phi when there are possibly other phis (i.e. the result
439446 /// might not be an expression).
440447 void simplifyStatementPhi (HBasicBlock block, HPhi phi) {
448+ if (simplifyStatementPhiToCommonInput (block, phi)) return ;
449+
450+ if (block.predecessors.length != 2 ) return ;
451+
441452 HBasicBlock dominator = block.dominator! ;
442453
443454 // Extract the controlling condition.
@@ -478,6 +489,52 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
478489 }
479490 }
480491
492+ bool simplifyStatementPhiToCommonInput (HBasicBlock block, HPhi phi) {
493+ // Replace phis that produce the same value on all arms. The test(s) for
494+ // control flow often results in a refinement instruction (HTypeKnown), so
495+ // we recognize that, allowing, e.g.,
496+ //
497+ // condition ? HTypeKnown(x) : x --> x
498+ // condition ? x : HTypeKnown(x) --> x
499+ //
500+ // We don't remove loop phis here. SsaRedundantPhiEliminator will eliminate
501+ // redundant phis without HTypeKnown refinements, including loop phis.
502+
503+ // There may be control flow that exits early, leaving refinements that
504+ // cause the type of the phi to be stronger than the source. Don't attempt
505+ // this simplification until the type of the phi is calculated.
506+ if (beforeTypePropagation) return false ;
507+
508+ HBasicBlock dominator = block.dominator! ;
509+
510+ /// Find the input, skipping refinements that do not dominate the condition,
511+ /// e.g., skipping refinements in the arm of the if-then-else.
512+ HInstruction ? dominatingRefinementInput (HInstruction input) {
513+ while (true ) {
514+ if (input.block! .dominates (dominator)) return input;
515+ if (input is ! HTypeKnown ) return null ;
516+ input = input.checkedInput;
517+ }
518+ }
519+
520+ final commonInput = dominatingRefinementInput (phi.inputs.first);
521+ if (commonInput == null ) return false ;
522+
523+ for (int i = 1 ; i < phi.inputs.length; i++ ) {
524+ final next = dominatingRefinementInput (phi.inputs[i]);
525+ if (! identical (next, commonInput)) return false ;
526+ }
527+
528+ HTypeKnown replacement = HTypeKnown .pinned (
529+ phi.instructionType,
530+ commonInput,
531+ );
532+ block.addBefore (block.first, replacement);
533+ block.rewrite (phi, replacement);
534+ block.removePhi (phi);
535+ return true ;
536+ }
537+
481538 /// Simplify some CFG diamonds to equivalent expressions.
482539 void simplifyExpressionPhi (HBasicBlock block, HPhi phi) {
483540 // Is [block] the join point for a simple diamond?
0 commit comments