summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/IfNode.java
blob: c83c81d053b4bf728f2cd46e4bcebfa8d7687ec5 (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.seaofnodes.simple.node;

import com.seaofnodes.print.ExprPrinter;

import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;

public class IfNode extends CFGNode implements MultiNode {

    public IfNode(Node ctrl, Node pred) {
        super(ctrl, pred);
        CodeGen.CODE.add(this); // Because idoms are complex, just add it
    }
    public IfNode(IfNode iff) { super(iff); }
    @Override public Tag serialTag() { return Tag.If; }

    @Override
    protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
        p.p("if( ");
        if( in(1)==null ) p.p("never");
        else p.n(in(1));
        return p.p(" )");
    }

    public Node ctrl() { return in(0); }
    public Node pred() { return in(1); }

    // No one unique control follows
    @Override public CFGNode uctrl() { return null; }

    @Override
    public Type compute() {
        // If the If node is not reachable then neither is any following Proj
        assert !_inputs.isEmpty();
        if (ctrl()._type != Type.CONTROL && ctrl()._type != Type.BOTTOM )
            return TypeTuple.IF_NEITHER;
        Node pred = pred();
        Type t = pred._type;
        // High types mean NEITHER side is reachable.
        // Wait until the type falls to decide which way to go.
        if( t.isHigh() )
            return TypeTuple.IF_NEITHER;
        // If constant is 0 then false branch is reachable
        // Else true branch is reachable
        if( t.isConstant() )
            return (t==Type.NIL || t==TypeInteger.ZERO || (t instanceof TypeFunPtr tfp && tfp._fidxs== XInt.EMPTY) ) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
        // If adding a zero makes a difference, the predicate must not have a zero/null
        if( !t.makeZero().isa(t) )
            return TypeTuple.IF_TRUE;

        return TypeTuple.IF_BOTH;
    }

    @Override
    public Node idealize() {
        // Hunt up the immediate dominator tree.  If we find an identical if
        // test on either the true or false branch, that side wins.
        if( !pred()._type.isHighOrConst() )
            for( CFGNode dom = idom(), prior=this; dom!=null;  prior = dom, dom = dom.idom() )
                if( addDep(dom) instanceof IfNode iff &&
                    prior instanceof CProjNode prj &&
                    (addDep(iff.pred())==pred() ||
                     pred() instanceof GuardNode cast && cast._nonZero && iff.pred()==cast.in(1) ) ) {
                    setDef(1,con( prj._idx==0 ? 1 : 0 ));
                    return this;
                }
        return null;
    }

    // MachNode variants need to support this and negate the conditional test.
    // The following CProjs will be inverted by the caller.
    public void negate() { throw Utils.TODO(); }

    // Negate the sense of a test
    public static String negate( String bop ) {
        return switch( bop ) {
        case "<"  -> ">=";
        case "<=" -> ">" ;
        case "==" -> "!=";
        case "!=" -> "==";
        case ">"  -> "<=";
        case ">=" -> "<" ;
        default -> throw Utils.TODO();
        };
    }

    // Swap compare operands
    public static String swap( String bop ) {
        return switch( bop ) {
        case "<"  -> ">" ;
        case "<=" -> ">=";
        case "==" -> "==";
        case "!=" -> "!=";
        case ">"  -> "<" ;
        case ">=" -> "<=";
        default -> throw Utils.TODO();
        };
    }
}