summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
blob: 9cb9ec1651b30590f1c0bf4490ee5141ba86ab03 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.seaofnodes.simple.codegen;

import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;

/** RegMask
 *  A "register mask" - 1 bit set for each allowed register.  In addition,
 *  "stack slot" registers may be allowed, effectively making the set infinite.
 * <p>
 *  For smaller and simpler machines it suffices to make such masks an i64 or
 *  i128 (64- or 128-bit integers), and this presentation is by far the better
 *  way to go... if all register allocations can fit in this bit limitation.
 *  The allocator will need bits for stack-based parameters and for splits
 *  which cannot get a register.  For a 32-register machine like the X86, add 1
 *  for flags - gives 33 registers.  Using a Java `long` has 64 bits, leaving
 *  31 for spills and stack passing.  This is adequate for nearly all
 *  allocations; only the largest allocations will run this out.  However, if
 *  we move to a chip with 64 registers we'll immediately run out, and need at
 *  least a 128 bit mask.  Since you cannot *return* a 128 bit value directly
 *  in Java, Simple will pick up a `RegMask` class object.
*/
public class RegMask {

    long _bits0, _bits1;

    private static final RegMask EMPTY = new RegMask(0L);
    public  static final RegMask FULL = new RegMask(-1L);

    public RegMask(int bit) {
        if( bit < 64 ) _bits0 = 1L<<bit;
        else _bits1 = 1L<<(bit-64);
    }
    public RegMask(long bits ) { _bits0 = bits; }
    public RegMask(long bits0, long bits1 ) { _bits0 = bits0; _bits1 = bits1; }
    public RegMask(RegMask r) { _bits0 = r._bits0; _bits1 = r._bits1; }

    // AND, with copy-on-write if changing
    RegMask and( RegMask mask ) {
        if( mask==null ) return this;
        long bits0 = _bits0 & mask._bits0;
        long bits1 = _bits1 & mask._bits1;
        if( bits0==_bits0 && bits1==_bits1 ) return this;
        if( bits0==mask._bits0 && bits1==mask._bits1 ) return mask;
        if( bits0==0 && bits1==0 ) return EMPTY;
        // Update-in-place a mutable mask, or make a defensive copy
        return null;
    }
    RegMask sub( RegMask mask ) {
        if( mask==null ) return this;
        long bits0 = _bits0 & ~mask._bits0;
        long bits1 = _bits1 & ~mask._bits1;
        if( bits0==_bits0 && bits1==_bits1 ) return this;
        if( bits0==mask._bits0 && bits1==mask._bits1 ) return mask;
        if( bits0==0 && bits1==0 ) return EMPTY;
        // Update-in-place a mutable mask, or make a defensive copy
        return null;
    }

    // Fails if bit is set, because this is immutable
    public boolean clr( int reg ) {
        if( reg <  64 ) return ((_bits0 >> reg)&1)==0;
        if( reg < 128 ) return ((_bits1 >> reg)&1)==0;
        return true;
    }


    public short firstReg() {
        if( isEmpty() ) return -1;
        return (short)(_bits0 != 0
                       ? Long.numberOfTrailingZeros(_bits0)
                       : Long.numberOfTrailingZeros(_bits1)+64);
    }
    public short nextReg(short reg) {
        if( reg < 63 ) {
            long bits0 = _bits0 & (-1L << (reg+1));
            if( bits0!=0 ) return (short)Long.numberOfTrailingZeros(bits0);
        }
        long bits1 = reg < 64 ? _bits1 : reg < 127 ? _bits1 & (-1L << (reg-63)) : 0;
        return bits1==0 ? -1 : (short)(64+Long.numberOfTrailingZeros(bits1));
    }

    boolean isEmpty() { return _bits0==0 && _bits1==0; }

    public boolean test( int reg ) {
        return ((reg<64 ? (_bits0 >> reg) : (_bits1 >> (reg-64))) & 1)  != 0;
    }

    // checks if the 2 masks have at least 1 bit in common
    public boolean overlap( RegMask mask ) { return (_bits0 & mask._bits0)!=0 || (_bits1 & mask._bits1)!=0; }

    // Defensive writable copy
    public RegMaskRW copy() { return new RegMaskRW( _bits0, _bits1 ); }

    // Has exactly 1 bit set
    public boolean size1() {
        return !isEmpty() && (((_bits0 & -_bits0)==_bits0 && _bits1==0) ||
                             ((_bits1 & -_bits1)==_bits1 && _bits0==0));
    }

    // Cardinality
    public short size() { return (short)(Long.bitCount(_bits0)+Long.bitCount(_bits1)); }

    @Override public String toString() { return toString(new SB()).toString(); }
    public SB toString(SB sb) {
        Machine mach = CodeGen.CODE._mach;
        if( _bits0==0 && _bits1==0 ) return sb.p("[]");
        sb.p("[");
        String[] regs = mach.regs();
        for( int i=0; i<64; i++ )
            if( ((_bits0 >> i)&1) != 0 )
                sb.p(reg(regs,i)).p(",");
        for( int i=0; i<64; i++ )
            if( ((_bits1 >> i)&1) != 0 )
                sb.p(reg(regs,i+64)).p(",");
        return sb.unchar().p("]");
    }

    public static String reg(String[] regs, int i) {
        return i<regs.length ? regs[i] : "[stk#"+i+"]";
    }
}