package com.seaofnodes.simple.node; import com.seaofnodes.print.ExprPrinter; import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.Serialize; import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.util.*; import java.util.HashMap; import java.util.IdentityHashMap; public class PhiNode extends Node { public final String _label; public PhiNode( String label, Node... inputs) { super(inputs); _label = label; } public static PhiNode make(String label, Type minType, Node... inputs) { return minType instanceof TypeMem mem ? mem._alias==1 ? new BulkMemPhiNode(label,inputs) : new MemPhiNode(label,mem._alias,inputs) : new PhiNode(label, inputs); } // Used by ParmNode public PhiNode(PhiNode phi, String label) { super(phi); _label = label; } // Used by instruction Selection public PhiNode(PhiNode phi) { this(phi,phi._label); } // Used by the infinite-loop exit breaker public PhiNode(RegionNode r, Node sample) { super(new Node[]{r}); _label = ""; _type = sample._type; while( nIns() < r.nIns() ) addDef(sample); } @Override public Tag serialTag() { return Tag.Phi; } @Override public void packed( BAOS baos, HashMap strs, HashMap types, IdentityHashMap anodes ) { baos.packed1(nIns()); baos.packed2(_label==null ? 0 : strs.get(_label)); } static Node make( BAOS bais, String[] strs, Type[] types) { Node[] ins = new Node[bais.packed1()]; return new PhiNode(strs[bais.packed2()], ins); } @Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); } @Override protected ExprPrinter _print1(ExprPrinter p) { if( !(region() instanceof RegionNode r) || r.inProgress() ) p.p("Z"); p.p("Phi("); for( Node in : _inputs ) p.n(in).p(","); return p.unchar(',').close(); } public CFGNode region() { return (CFGNode)in(0); } @Override public boolean isMem() { return _type instanceof TypeMem; } @Override public Type compute() { if( !(region() instanceof RegionNode r) ) return Type.TOP; // During parsing Phis have to be computed type pessimistically. if( r.inProgress() || in(nIns()-1)==null ) return Type.BOTTOM; // Set type to local top of the starting type Type t = Type.TOP; for( int i = 1; i < nIns(); i++ ) { // If the region's control input is live, add this as a dependency // to the control because we can be peeped should it become dead. Type ctrl = addDep(r.in(i))._type; if( ctrl != Type.XCONTROL && ctrl != Type.TOP ) { if( in(i)._type==Type.BOTTOM ) return Type.BOTTOM; t = t.meet(in(i)._type); } } // Above-center ranges may still fall to unwidened constants. // Widen only below-center ranges to preserve monotonicity. if( r instanceof LoopNode && // Only around loops t instanceof TypeInteger ti && // Only widen integers !ti.isHigh() && !ti.isConstant() ) { // Only widen live ranges // Widen, to prevent infinite falling of TypeIntegers return ti.same_but_slightly_wider_than(); } return t; } @Override public Node idealize() { RegionNode r = (RegionNode)region(); if( r.inProgress() || nOuts()==0 ) return null; // Input is in-progress // If we have only a single unique input, become it. Node live = singleUniqueInput(); if( live != null ) return live; // No bother if region is going to fold dead paths soon for( int i=1; i1 ) { for( Node use : n._outputs ) if( use!=null && use!=this ) addDepForwards(use); if( n instanceof StoreNode || busy!=null ) return false; busy=n; } for( int j=1; j strs ) { Serialize.gather(strs,_label); } }