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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
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.codegen.GlobalBits;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
import java.lang.StringBuilder;
import java.util.BitSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
/**
* Convenience common base for Load and Store.
*
* 0 - Control
* 1 - Memory
* 2 - Base of object, OOP
* 3 - Offset, integer types
* 4 - Value, for Stores only
*/
public abstract class MemOpNode extends TypeNode {
// The equivalence alias class
public int _alias;
// True if load-like, false if store-like.
// Used on CPU-specific combined memory+arithmetic ops.
//
// Stores produce memory (maybe as part of a tuple with other things),
// loads do not.
//
// Loads might pick up anti-dependencies on prior Stores, and never cause an
// anti-dependence themselves.
//
// Stores must maximally sink to the least dominator use. Loads can be
// opportunistically hoisted.
public final boolean _isLoad;
// Field name.
public final String _name;
// Source location for late reported errors
public final Parser.Lexer _loc;
public MemOpNode(Parser.Lexer loc, String name, int alias, boolean isLoad, Type decl, Node ctrl, Node mem, Node ptr, Node off) {
super(decl, ctrl, mem, ptr, off);
_name = name;
_alias = alias;
_loc = loc;
_isLoad = isLoad;
}
public MemOpNode(Parser.Lexer loc, String name, int alias, boolean isLoad, Type decl, Node ctrl, Node mem, Node ptr, Node off, Node value) {
this(loc, name, alias, isLoad, decl, ctrl, mem, ptr, off);
addDef(value);
}
public MemOpNode( Node ideal, MemOpNode mop ) {
super(ideal,mop instanceof LoadNode ld ? ld.declaredType() : mop._con);
_name = mop._name;
_alias = mop._alias;
_loc = mop._loc;
_isLoad= mop._isLoad;
}
MemOpNode( BAOS bais, String[] strs, Type[] types, GlobalBits fileAliases, GlobalBits aliases, boolean isLoad ) {
this(null,
strs[bais.packed2()],
mapAlias(bais,fileAliases,aliases),isLoad,
types[bais.packed2()],null,null,null,null);
}
private static int mapAlias( BAOS bais, GlobalBits fileAliases, GlobalBits aliases ) {
int alias = bais.packed2();
return alias < GlobalBits.RESERVED ? alias : aliases.map(fileAliases,alias);
}
@Override public void packed( BAOS baos, HashMap<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node, Integer> anodes ) {
baos.packed2(_name==null ? 0 : strs.get(_name));
baos.packed2(_alias);
baos.packed2(types.get(_con)); // NPE if fails lookup
assert _isLoad == this instanceof LoadNode; // No machine ops
}
static String mlabel(String name) { return "[]"==name ? "ary" : ("#"==name ? "len" : name); }
String mlabel() { return mlabel(_name); }
public Node mem() { return in(1); }
public Node ptr() { return in(2); }
public Node off() { return in(3); }
// Current declared field type. This is deliberately a live lookup:
// cyclic/forward types can sharpen by replacing the pointer's struct.
public Type declaredType() {
if( !(ptr()._type instanceof TypeMemPtr tmp) )
return Type.BOTTOM;
Field fld = tmp._obj.field(_name);
return fld == null || fld._t == null ? Type.BOTTOM : fld._t;
}
@Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); }
protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); }
// Extra conditions for factoring matching memory operations through a Phi.
// The caller has already checked the opcode, input shape and control.
boolean canDrop(MemOpNode other, Node dep) {
dep.addDep(ptr());
return _alias>1 && _alias==other._alias && declaredType()==other.declaredType() && err()==null;
}
@Override
public boolean eq(Node n) {
MemOpNode mem = (MemOpNode)n; // Invariant
return _alias==mem._alias && super.eq(mem);
}
@Override
int hash() { return _alias ^ super.hash(); }
@Override
public Parser.ParseException err() {
Type ptr = ptr()._type;
// Already an error, but better error messages come from elsewhere
if( ptr == Type.BOTTOM ) return null;
if( ptr.isHigh() ) return null; // Assume it will fall to not-null
// Better be a not-nil TMP
if( !(ptr instanceof TypeMemPtr tmp && tmp.notNull()) )
return Parser.error( "Might be null accessing '" + _name + "'",_loc);
if( tmp._obj.field(_name)==null &&
CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Opto.ordinal() )
return Parser.error("Accessing unknown field '"+_name+"' from '*"+tmp._obj._name+"'",_loc);
// Sane field
if( off() instanceof ConFldOffNode && CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Opto.ordinal() )
return Parser.error("Accessing unknown field '"+_name+"' from '*"+tmp._obj._name+"'",_loc);
return null;
}
// Memory writers which must follow this read. A packaging node is not a
// write; follow this alias through aggregates to its writers.
public ArrayList<Node> antiDeps() {
ArrayList<Node> deps = new ArrayList<>();
antiDeps(mem(),deps,new BitSet());
return deps;
}
private void antiDeps(Node mem, ArrayList<Node> deps, BitSet visit) {
if( visit.get(mem._nid) ) return;
visit.set(mem._nid);
for( Node use : mem._outputs ) {
if( use instanceof MemMergeNode merge ) {
Node slice = _alias<merge.nIns() ? merge.in(_alias) : null;
if( (slice==mem) || (slice==null && merge.in(1)==mem) )
antiDeps(merge,deps,visit);
} else if( use instanceof CallNode ||
(use instanceof MemOpNode st && !st._isLoad && st._alias==_alias) ||
(use instanceof EscapeNode esc && esc.fld()._alias==_alias) ||
(use instanceof MemPhiNode phi && phi._alias==_alias) ||
(use instanceof BulkMemPhiNode phi && !phi.isSplit(_alias)) ) {
if( !deps.contains(use) ) deps.add(use);
}
}
}
}
|