summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java
blob: 0b31497878d891cb590a02c7a2b4a7c6de889131 (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
101
package com.seaofnodes.simple.codegen;

import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;

abstract public class BuildLRG {
    // Compute live ranges in a single forwards pass.  Every def is a new live
    // range except live ranges are joined at Phi.  Also, gather the
    // intersection of register masks in each live range.  Example: "free
    // always zero" register forces register zero, and calling conventions
    // typically force registers.

    // Sets FAILED to the set of hard-conflicts (means no need for an IFG,
    // since it will not color, just split the conflicted ranges now).  Returns
    // true if no hard-conflicts, although we still might not color.
    public static boolean run(int round, RegAlloc alloc) {
        FunNode fun = null;
        for( Node bb : alloc._code._cfg ) {
            if( bb instanceof FunNode fun2 )
                fun = fun2;
            for( Node n : bb.outs() ) {
                // A synthetic never-exit value has no runtime definition.
                if( n._type==Type.TOP ) continue;
                if( n instanceof PhiNode phi && !(phi._type instanceof TypeMem) ) {
                    if( phi instanceof MachNode mach && mach.outregmap()==null )
                        continue;
                    // All real Phi inputs end up with the same LRG.
                    // Pass 1: find any pre-existing LRG, to avoid make-then-Union a LRG
                    LRG lrg = alloc.lrg(phi);
                    if( lrg == null )
                        for( int i=1; i<phi.nIns(); i++ )
                            if( (lrg = alloc.lrg(phi.in(i))) != null )
                                break;
                    // If none, make one.
                    if( lrg==null ) lrg = alloc.newLRG(n,fun);
                    if( phi instanceof MachNode ) defLRG(alloc,n,fun);
                    // Pass 2: everybody uses the same LRG
                    lrg=alloc.union(lrg,phi);
                    for( int i=phi instanceof ParmNode ? 2 : 1; i<n.nIns(); i++ )
                        // TOP keeps the type merge neutral, but needs no register.
                        if( n.in(i)._type!=Type.TOP )
                            lrg=alloc.union(lrg,n.in(i));
                    if( lrg._mask!=null && lrg._mask.isEmpty() )
                        alloc.fail(lrg);

                } else if( n instanceof MachNode mach ) {
                    // Attempt to commute ops to keep live ranges compatible.
                    if( mach.commutes() && n.nOuts()==1 ) {
                        int uidx = n.out(0)._inputs.find(n);
                        RegMask mask1 = n.in (1) instanceof MachNode machx ? machx.outregmap() : alloc.lrg(n.in(1))._mask;
                        RegMask mask2 = n.in (2) instanceof MachNode machx ? machx.outregmap() : alloc.lrg(n.in(2))._mask;
                        RegMask masko = n.out(0) instanceof MachNode machx ? machx.regmap(uidx): mach.outregmap();
                        if( masko!=null && !mask1.overlap(masko) && mask2.overlap(masko) )
                            n.swap12();
                    }

                    // Define live range
                    defLRG(alloc,n,fun);

                    // Now, look in the opposite direction. How are incoming
                    // LRGs affected by this node: For all uses, make live lrgs
                    for( int i=1; i<n.nIns(); i++ )
                        if( n.in(i)!=null ) {
                            LRG lrg2 = alloc.lrg(n.in(i));
                            if( lrg2 != null ) { // Anti-dep or other, no LRG
                                RegMask use_mask = mach.regmap(i); // use_mask is also null for anti-dep
                                if( use_mask!=null && !lrg2.machUse(mach,(short)i,use_mask.size1()).and(use_mask) )
                                    alloc.fail(lrg2); // Empty register mask, must split
                            }
                        }

                }

                // MultiNodes have projections which set registers
                if( n instanceof MultiNode && !(n instanceof CFGNode) )
                    for( Node proj : n.outs() )
                        if( proj instanceof MachNode )
                            defLRG(alloc,proj,fun);
            }
        }

        // Collect live ranges
        alloc.unify();

        return alloc.success();
    }

    private static void defLRG( RegAlloc alloc, Node n, FunNode fun ) {
        MachNode mach = (MachNode)n;
        RegMask def_mask = mach.outregmap();
        if( def_mask == null ) return;
        LRG lrg = mach.twoAddress() == 0
            ? alloc.newLRG(n,fun)              // Define a new LRG for N
            : alloc.lrg2(n,mach.twoAddress()); // Use the matching 2-adr input
        // Record mask and mach
        if( !lrg.machDef(mach,def_mask.size1()).and(def_mask) )
            alloc.fail(lrg); // Empty register mask, must split
    }

}