summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
blob: f94fa48478b6ddd10b291bed2eda5aa1bd1e8155 (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
package com.seaofnodes.simple.node;

import com.seaofnodes.print.ExprPrinter;

import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeStruct;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
import java.util.HashMap;

/**
 * A field offset.  This becomes a constant *after* other optimizations which
 * determine field sizes - some fields might be dead, or hold only zeros or
 * small values.
 */

public class ConFldOffNode extends ConstantNode {
    public TypeStruct _ts;      // Struct holding field
    public final String _fname; // Field name
    public ConFldOffNode( TypeStruct ts, String fname ) { super(TypeInteger.BOT); _ts = ts; _fname = fname; }
    @Override public Tag serialTag() { throw Utils.TODO("should not reach here"); }

    @Override public String label() {
        return _fname == " len" ? "sizeof("+_ts._name+")" : "#"+_fname;
    }

    @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
        return p.p(label());
    }

    @Override public Node idealize() {
        // Some array offsets are known early
        if( _ts.isAry() ) {
            // Length always at offset zero
            if( _fname==" len" )
                return CodeGen.CODE.ZERO;
            // The shift depends on the element
            if( _fname=="<<" )
                return Node.con(_ts.aryScale());
            // The base depends on the layout (alignment for large elements may
            // involve padding) and MAY depend on the length if I go for
            // smaller array lengths.
        }
        return null;
    }

    // Convert field offset to an integer
    public Node asOffset() {
        int fldx = _fname==" len" ? _ts._fields.length : _ts.find(_fname);
        if( fldx == -1 ) return null;
        // " len" selects the terminal size slot, not a Field.
        if( fldx < _ts._fields.length && _ts._fields[fldx]._extern )
            return new ExternOffsetNode(_fname).peephole();
        return ConstantNode.make(TypeInteger.constant(_ts.offset(fldx))).peephole();
    }

    // Upgrade the internal type
    @Override boolean _upgradeType( HashMap<String,Type> TYPES) {
        boolean progress = super._upgradeType(TYPES);
        TypeStruct ts = (TypeStruct)_ts.upgradeType(TYPES);
        if( ts == _ts ) return progress;
        _ts = ts;
        return true;
    }

    @Override public boolean eq(Node n) {
        ConFldOffNode off = (ConFldOffNode)n; // Invariant
        return _ts._name==off._ts._name && _fname.equals(off._fname) && super.eq(n);
    }
    @Override int hash() { return super.hash() * _ts._name.hashCode() * _fname.hashCode(); }
}