summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/GuardNode.java
blob: 0ce504d9f0c8ba63868eb07fd38af3f5f466f132 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node,Integer> 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<Node> _print1(ExprPrinter<Node> 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; }
}