package com.seaofnodes.simple.node; import com.seaofnodes.print.ExprPrinter; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeScalar; import com.seaofnodes.simple.util.BAOS; import com.seaofnodes.simple.util.Utils; import java.util.HashMap; import java.util.IdentityHashMap; // A branch-proven refinement to zero/null or non-zero/non-null. The value // family is deliberately taken from the input when it becomes known. public class GuardNode extends Node { public final boolean _nonZero; public GuardNode(boolean nonZero, Node ctrl, Node val) { super(ctrl,val); _nonZero = nonZero; } public GuardNode(GuardNode guard) { super(guard); _nonZero = guard._nonZero; } @Override public Tag serialTag() { return Tag.Guard; } @Override public void packed(BAOS baos, HashMap strs, HashMap types, IdentityHashMap anodes) { baos.write(_nonZero ? 1 : 0); } static Node make(BAOS bais) { return new GuardNode(bais.read()!=0,null,null); } @Override public String label() { return _nonZero ? "(!=0)" : "(==0)"; } @Override protected ExprPrinter _print1(ExprPrinter p) { return p.p(label()).n(in(1)); } @Override public Type compute() { // Guard is a pinned, path-local fact. If its control path is not // executable, the fact is not executable either, regardless of how the // value input sharpens later. Type c = in(0)._type; if( c != Type.CONTROL && c != Type.BOTTOM ) return Type.TOP; Type t = in(1)._type; if( t==Type.BOTTOM || t==Type.TOP ) return t; // The scalar envelope does not identify a value family. Preserve it // until SCCP learns whether this is an int, float, pointer, or fptr; // choosing generic ptr here can be weaker than a later concrete type. if( t==TypeScalar.BOT || t==TypeScalar.TOP ) return t; Type t2 = _nonZero ? t.nonZero() : t.makeZero(); return t2==null ? (_type==null ? Type.TOP : _type) : t2; // No sane answer for e.g. not-zero of a zero } @Override public Node idealize() { if( in(0)._type != Type.CONTROL && in(0)._type != Type.BOTTOM ) return null; if( in(1)._type==Type.BOTTOM || in(1)._type==Type.TOP ) return null; if( _type.isHighOrConst() && in(1)._type.isa(_type) ) return in(1); return null; } @Override public boolean eq(Node n) { return _nonZero==((GuardNode)n)._nonZero; } @Override int hash() { return _nonZero ? 1 : 0; } }