aa
HM2.java
Go to the documentation of this file.
1 package com.cliffc.aa.HM;
2 
3 import com.cliffc.aa.type.*;
4 import com.cliffc.aa.util.SB;
5 import com.cliffc.aa.util.VBitSet;
6 
7 import java.util.Arrays;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 
11 // Hindley-Milner typing. Complete stand-alone, for research. MEETs base
12 // types, instead of declaring type error. Requires SSA renumbering; uses a
13 // global Env instead locally tracking.
14 //
15 // For Sea-of-Nodes, plus memory/side-effects:
16 // Buff for multi-args AND multi-return (return includes memory).
17 // LAMBDA/FunNode:
18 // Parms: new TVar per Parm.
19 // Ret : Gather multi-return TVars (ret&mem)
20 // TFP : new TVar == { parms... -> ret mem }
21 // APPLY/CallNode:
22 // Clone TFP fresh (clone-per-use), and the TFP has to be sorted out already.
23 // Build TVarFun { args... mem -> new rez, new mem }
24 // U-F with cloned TFP. Cloned TFP has constraints like input-same-type-as-
25 // output, and U-F enforces this on Call args.
26 // IDENT/Node:
27 // Clone per use typically, so put the onus on the user.
28 // Otherwise use TNode (which is base Type for this Node).
29 
30 // Thinking: every Node USE (occurrence of an Ident) gets a unique TVar - except
31 // TFP's being used inside their own Fun (recursive). This is a TVar-per-Edge
32 // instead of per-Node.
33 //
34 // Also: Arrays need recursive-MEET same as Structs. Much simpler, of course!
35 // But ptrs-to-Arrays-to-ptrs of the same type should totally be typable.
36 //
37 // Also: TFPs need a TVar per arg & return; so do TypeStruct need a TVar per
38 // field. Correlation between NewStruct having an Edge-per-Field.
39 //
40 // Must run HM after first GCP (coarse Call Graph available).
41 // But wondering if can run DURING GCP & get optimistic results.
42 // HM is NOT the same as Thesis combo.
43 
44 // Starting with pessimistic: TVars allow JOIN on types in some places lifting
45 // conservative answers. They discover congruences (equivs) amongst Nodes,
46 // and can be used to lift values amongst congruences; e.g., if A===B and
47 // A:int:3 and B:BOTTOM, actually B:int:3.
48 
49 // TypeNode: has a Node & can UF with other TypeNodes. Computes base type as a
50 // JOIN across all UF Nodes' base types. Nodes start with a TypeNode of
51 // themselves. Identities can UF TypeNodes for their own TypeNode. SESE
52 // regions can lift TypeNodes around Phi/Parm. NewObj has a TypeNode which is
53 // a TypeStruct with TypeNode fields. Fun has a TypeNode which is a TypeFunSig
54 // which has args & ret as TypeNodes. So TypeNodes have mirror structure to
55 // Types??? So... maybe want Rule: Node has a Type (which includes a TypeNode),
56 // but Nodes' TypeNode cannot (recursively) encode its own TypeNode.
57 //
58 // Ex: Con:int:5 - TypeInt:5.
59 // Ex: (Add x y) - TypeInt:int64
60 // Ex: (Copy a) - TypeNode:a, where 'a' is not this Copy
61 // Ex: Parm - Type as a MEET of inputs, not a TypeNode, unless foldable (which Ideal will do).
62 // Ex: Ret - TypeTuple of {ret:TypeNode, mem:TypeNode}
63 // Ex: CallEpi - TypeTuple of MEET of {ret:TypeNode, mem:TypeNode}.
64 // Ex: CallEpi - Single ret; for all TypeNodes in {ret,mem} that are Parm, replace with Call edge.
65 
66 
67 public class HM2 {
68  static final HashMap<String,HMType> ENV = new HashMap<>();
69 
70  public static HMType hm( Syntax prog) {
71  // Simple types
72  HMVar bool = new HMVar(TypeInt.BOOL);
73  HMVar int64 = new HMVar(TypeInt.INT64);
74  HMVar flt64 = new HMVar(TypeFlt.FLT64);
75  HMVar strp = new HMVar(TypeMemPtr.STRPTR);
76 
77  // Primitives
78  HMVar var1 = new HMVar();
79  HMVar var2 = new HMVar();
80  ENV.put("pair",Oper.fun(var1, Oper.fun(var2, new Oper("pair",var1,var2))));
81 
82  HMVar var3 = new HMVar();
83  ENV.put("if/else",Oper.fun(bool,Oper.fun(var3,Oper.fun(var3,var3))));
84 
85  ENV.put("dec",Oper.fun(int64,int64));
86  ENV.put("*",Oper.fun(int64,Oper.fun(int64,int64)));
87  ENV.put("==0",Oper.fun(int64,bool));
88 
89  // Print a string; int->str
90  ENV.put("str",Oper.fun(int64,strp));
91  // Factor
92  ENV.put("factor",Oper.fun(flt64,new Oper("pair",flt64,flt64)));
93 
94 
95  // Prep for SSA: pre-gather all the (unique) ids
96  prog.get_ids();
97 
98  return prog.hm(new HashSet<>());
99  }
100  static void reset() { HMVar.reset(); }
101 
102 
103  public static abstract class Syntax {
104  abstract HMType hm(HashSet<HMVar> nongen);
105  abstract void get_ids();
106  }
107  public static class Con extends Syntax {
108  final Type _t;
109  Con(Type t) { _t=t; }
110  @Override public String toString() { return _t.toString(); }
111  @Override HMType hm(HashSet<HMVar> nongen) { return new HMVar(_t); }
112  @Override void get_ids() {}
113  }
114  public static class Ident extends Syntax {
115  final String _name;
116  Ident(String name) { _name=name; }
117  @Override public String toString() { return _name; }
118  @Override HMType hm(HashSet<HMVar> nongen) {
119  HMType t = ENV.get(_name);
120  if( t==null )
121  throw new RuntimeException("Parse error, "+_name+" is undefined");
122  HMType f = t.fresh(nongen);
123  return f;
124  }
125  @Override void get_ids() {}
126  }
127  public static class Lambda extends Syntax {
128  final String _arg0;
129  final Syntax _body;
130  Lambda(String arg0, Syntax body) { _arg0=arg0; _body=body; }
131  @Override public String toString() { return "{ "+_arg0+" -> "+_body+" }"; }
132  @Override HMType hm(HashSet<HMVar> nongen) {
133  HMVar tnew = (HMVar) ENV.get(_arg0);
134  nongen.add(tnew);
135  HMType trez = _body.hm(nongen);
136  nongen.remove(tnew);
137  return Oper.fun(tnew,trez);
138  }
139  @Override void get_ids() { ENV.put(_arg0, new HMVar()); _body.get_ids(); }
140  }
141  public static class Let extends Syntax {
142  final String _arg0;
143  final Syntax _body, _use;
144  Let(String arg0, Syntax body, Syntax use) { _arg0=arg0; _body=body; _use=use; }
145  @Override public String toString() { return "let "+_arg0+" = "+_body+" in "+_use+" }"; }
146  @Override HMType hm(HashSet<HMVar> nongen) {
147  HMVar tnew = (HMVar) ENV.get(_arg0);
148  nongen.add(tnew);
149  HMType tbody = _body.hm(nongen);
150  nongen.remove(tnew);
151  tnew.union(tbody);
152  HMType trez = _use.hm(nongen);
153  return trez;
154  }
155  @Override void get_ids() { ENV.put(_arg0, new HMVar()); _use.get_ids(); _body.get_ids(); }
156  }
157  public static class Apply extends Syntax {
158  final Syntax _fun, _arg;
159  Apply(Syntax fun, Syntax arg) { _fun=fun; _arg=arg; }
160  @Override public String toString() { return "("+_fun+" "+_arg+")"; }
161  @Override HMType hm(HashSet<HMVar> nongen) {
162  HMType tfun = _fun.hm(nongen);
163  HMType targ = _arg.hm(nongen);
164  HMType trez = new HMVar();
165  HMType nfun = Oper.fun(targ,trez);
166  nfun.union(tfun);
167  return trez;
168  }
169  @Override void get_ids() { _fun.get_ids(); _arg.get_ids(); }
170  }
171 
172 
173 
174  public static abstract class HMType {
175  HMType _u; // U-F; always null for Oper
176  abstract HMType union(HMType t);
177  abstract HMType find();
178  public String str() { return find()._str(); }
179  abstract String _str();
180  boolean is_top() { return _u==null; }
181 
182  HMType fresh(HashSet<HMVar> nongen) {
183  HashMap<HMType,HMType> vars = new HashMap<>();
184  return _fresh(nongen,vars);
185  }
186  HMType _fresh(HashSet<HMVar> nongen, HashMap<HMType,HMType> vars) {
187  HMType t2 = find();
188  if( t2 instanceof HMVar ) {
189  return t2.occurs_in(nongen) //
190  ? t2 // Keep same var
191  : vars.computeIfAbsent(t2, e -> new HMVar(((HMVar)t2)._t));
192  } else {
193  Oper op = (Oper)t2;
194  HMType[] args = new HMType[op._args.length];
195  for( int i=0; i<args.length; i++ )
196  args[i] = op._args[i]._fresh(nongen,vars);
197  return new Oper(op._name,args);
198  }
199  }
200 
201  boolean occurs_in(HashSet<HMVar>nongen) {
202  for( HMVar x : nongen ) if( occurs_in_type(x) ) return true;
203  return false;
204  }
205  boolean occurs_in(HMType[] args) {
206  for( HMType x : args ) if( occurs_in_type(x) ) return true;
207  return false;
208  }
209  boolean occurs_in_type(HMType v) {
210  assert is_top();
211  HMType y = v.find();
212  if( y==this )
213  return true;
214  if( y instanceof Oper )
215  return occurs_in(((Oper)y)._args);
216  return false;
217  }
218  }
219 
220  static class HMVar extends HMType {
221  private Type _t;
222  private final int _uid;
223  private static int CNT;
224  HMVar() { this(Type.ANY); }
225  HMVar(Type t) { _uid=CNT++; _t=t; }
226  static void reset() { CNT=1; }
227  public Type type() { assert is_top(); return _t; }
228  @Override public String toString() {
229  String s = _str();
230  if( _u!=null ) s += ">>"+_u;
231  return s;
232  }
233  @Override public String _str() {
234  String s = "v"+_uid;
235  if( _t!=Type.ANY ) s += ":"+_t.str(new SB(),new VBitSet(),null,false);
236  return s;
237  }
238 
239  @Override HMType find() {
240  HMType u = _u;
241  if( u==null ) return this; // Top of union tree
242  if( u._u==null ) return u; // One-step from top
243  // Classic U-F rollup
244  while( u._u!=null ) u = u._u; // Find the top
245  HMType x = this; // Collapse all to top
246  while( x._u!=u ) { HMType tmp = x._u; x._u=u; x=tmp;}
247  return u;
248  }
249  @Override HMType union(HMType that) {
250  if( _u!=null ) return find().union(that);
251  if( that instanceof HMVar ) that = that.find();
252  if( this==that ) return this; // Do nothing
253  if( occurs_in_type(that) )
254  throw new RuntimeException("recursive unification");
255 
256  if( that instanceof HMVar ) {
257  HMVar v2 = (HMVar)that;
258  v2._t = _t.meet(v2._t);
259  }
260  else assert _t==Type.ANY; // Else this var is un-MEETd with any Con
261  return _u = that; // Classic U-F union
262  }
263  }
264 
265  static class Oper extends HMType {
266  final String _name;
267  final HMType[] _args;
268  Oper(String name, HMType... args) { _name=name; _args=args; }
269  static Oper fun(HMType... args) { return new Oper("->",args); }
270  @Override public String toString() {
271  if( _name.equals("->") ) return "{ "+_args[0]+" -> "+_args[1]+" }";
272  return _name+" "+Arrays.toString(_args);
273  }
274  @Override public String _str() {
275  if( _name.equals("->") )
276  return "{ "+_args[0].str()+" -> "+_args[1].str()+" }";
277  SB sb = new SB().p(_name).p('(');
278  for( HMType t : _args )
279  sb.p(t.str()).p(',');
280  return sb.unchar().p(')').toString();
281  }
282 
283  @Override HMType find() { return this; }
284  @Override HMType union(HMType that) {
285  if( !(that instanceof Oper) ) return that.union(this);
286  Oper op2 = (Oper)that;
287  if( !_name.equals(op2._name) ||
288  _args.length != op2._args.length )
289  throw new RuntimeException("Cannot unify "+this+" and "+that);
290  for( int i=0; i<_args.length; i++ )
291  _args[i].union(op2._args[i]);
292  return this;
293  }
294  }
295 }
com.cliffc.aa.HM.HM2.Let.toString
String toString()
Definition: HM2.java:145
com.cliffc.aa.HM.HM2.Let._arg0
final String _arg0
Definition: HM2.java:142
com.cliffc.aa.HM.HM2.Apply
Definition: HM2.java:157
com.cliffc.aa.HM.HM2.HMVar.CNT
static int CNT
Definition: HM2.java:223
com.cliffc.aa.HM.HM2.Let._use
final Syntax _use
Definition: HM2.java:143
com.cliffc.aa.HM.HM2.Ident
Definition: HM2.java:114
com.cliffc.aa.HM.HM2.HMType._u
HMType _u
Definition: HM2.java:175
com.cliffc.aa.HM.HM2.Con.hm
HMType hm(HashSet< HMVar > nongen)
Definition: HM2.java:111
com.cliffc
com.cliffc.aa.type.Type.toString
final String toString()
Definition: Type.java:127
com.cliffc.aa.HM.HM2.Ident.hm
HMType hm(HashSet< HMVar > nongen)
Definition: HM2.java:118
com.cliffc.aa.HM.HM2.Syntax
Definition: HM2.java:103
com.cliffc.aa.util
Definition: AbstractEntry.java:1
com.cliffc.aa.HM.HM2.Ident._name
final String _name
Definition: HM2.java:115
com.cliffc.aa.type.TypeInt
Definition: TypeInt.java:9
com.cliffc.aa.type.Type
an implementation of language AA
Definition: Type.java:94
com.cliffc.aa.HM.HM2.Ident.get_ids
void get_ids()
Definition: HM2.java:125
com.cliffc.aa.HM.HM2.ENV
static final HashMap< String, HMType > ENV
Definition: HM2.java:68
com.cliffc.aa.type.TypeFlt
Definition: TypeFlt.java:9
com.cliffc.aa.HM.HM2.HMType.is_top
boolean is_top()
Definition: HM2.java:180
com.cliffc.aa.HM.HM2.Con._t
final Type _t
Definition: HM2.java:108
com.cliffc.aa.HM.HM2.Lambda.get_ids
void get_ids()
Definition: HM2.java:139
com.cliffc.aa.HM.HM2.Lambda._arg0
final String _arg0
Definition: HM2.java:128
com.cliffc.aa.type.Type.ANY
static final Type ANY
Definition: Type.java:325
com.cliffc.aa.HM.HM2.Apply.Apply
Apply(Syntax fun, Syntax arg)
Definition: HM2.java:159
com.cliffc.aa.HM.HM2.Let.Let
Let(String arg0, Syntax body, Syntax use)
Definition: HM2.java:144
com.cliffc.aa.type.Type.meet
final Type meet(Type t)
Definition: Type.java:412
com.cliffc.aa.type.Type.str
SB str(SB sb, VBitSet dups, TypeMem mem, boolean debug)
Definition: Type.java:131
com.cliffc.aa.HM.HM2.HMType.union
abstract HMType union(HMType t)
com.cliffc.aa.HM.HM2.HMType._fresh
HMType _fresh(HashSet< HMVar > nongen, HashMap< HMType, HMType > vars)
Definition: HM2.java:186
com.cliffc.aa.HM.HM2.Syntax.hm
abstract HMType hm(HashSet< HMVar > nongen)
com.cliffc.aa.HM.HM2.Let._body
final Syntax _body
Definition: HM2.java:143
com.cliffc.aa.HM.HM2.HMVar.HMVar
HMVar()
Definition: HM2.java:224
com.cliffc.aa.HM.HM2.Apply._arg
final Syntax _arg
Definition: HM2.java:158
com.cliffc.aa.util.SB.unchar
SB unchar()
Definition: SB.java:58
com.cliffc.aa.HM.HM2.Oper.find
HMType find()
Definition: HM2.java:283
com.cliffc.aa.HM.HM2.Ident.toString
String toString()
Definition: HM2.java:117
com.cliffc.aa.HM.HM2.Con.Con
Con(Type t)
Definition: HM2.java:109
com.cliffc.aa.type.TypeInt.INT64
static final TypeInt INT64
Definition: TypeInt.java:39
com.cliffc.aa.HM.HM2.Oper.toString
String toString()
Definition: HM2.java:270
com.cliffc.aa.HM.HM2.HMType.occurs_in
boolean occurs_in(HashSet< HMVar >nongen)
Definition: HM2.java:201
com.cliffc.aa.HM.HM2.Syntax.get_ids
abstract void get_ids()
com.cliffc.aa.HM.HM2.Con.toString
String toString()
Definition: HM2.java:110
com.cliffc.aa.HM.HM2.HMType.str
String str()
Definition: HM2.java:178
com.cliffc.aa.HM.HM2.HMType.find
abstract HMType find()
com.cliffc.aa.HM.HM2.Oper._name
final String _name
Definition: HM2.java:266
com.cliffc.aa.HM.HM2.HMVar.toString
String toString()
Definition: HM2.java:228
com.cliffc.aa.HM.HM2.Lambda.Lambda
Lambda(String arg0, Syntax body)
Definition: HM2.java:130
com.cliffc.aa.HM.HM2.Apply._fun
final Syntax _fun
Definition: HM2.java:158
com.cliffc.aa.HM.HM2.HMType
Definition: HM2.java:174
com.cliffc.aa.HM.HM2.HMVar._uid
final int _uid
Definition: HM2.java:222
com.cliffc.aa.HM.HM2.HMType.occurs_in_type
boolean occurs_in_type(HMType v)
Definition: HM2.java:209
com.cliffc.aa.HM.HM2.reset
static void reset()
Definition: HM2.java:100
com.cliffc.aa.HM.HM2.HMVar._t
Type _t
Definition: HM2.java:221
com.cliffc.aa.util.VBitSet
Definition: VBitSet.java:5
com.cliffc.aa.util.SB
Tight/tiny StringBuilder wrapper.
Definition: SB.java:8
com.cliffc.aa.HM.HM2.Let.hm
HMType hm(HashSet< HMVar > nongen)
Definition: HM2.java:146
com.cliffc.aa.HM.HM2.Let
Definition: HM2.java:141
com.cliffc.aa.HM.HM2.Lambda._body
final Syntax _body
Definition: HM2.java:129
com.cliffc.aa.HM.HM2.Apply.hm
HMType hm(HashSet< HMVar > nongen)
Definition: HM2.java:161
com.cliffc.aa.HM.HM2.Oper._str
String _str()
Definition: HM2.java:274
com.cliffc.aa.HM.HM2.Con
Definition: HM2.java:107
com.cliffc.aa.HM.HM2.Apply.get_ids
void get_ids()
Definition: HM2.java:169
com.cliffc.aa.HM.HM2.Con.get_ids
void get_ids()
Definition: HM2.java:112
com.cliffc.aa.HM.HM2.HMVar.union
HMType union(HMType that)
Definition: HM2.java:249
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.HM.HM2.HMVar.reset
static void reset()
Definition: HM2.java:226
com.cliffc.aa.util.SB.p
SB p(String s)
Definition: SB.java:13
com.cliffc.aa.HM.HM2
Definition: HM2.java:67
com.cliffc.aa.HM.HM2.HMType.occurs_in
boolean occurs_in(HMType[] args)
Definition: HM2.java:205
com.cliffc.aa.HM.HM2.HMVar.HMVar
HMVar(Type t)
Definition: HM2.java:225
com.cliffc.aa.HM.HM2.HMVar.type
Type type()
Definition: HM2.java:227
com.cliffc.aa.HM.HM2.Oper.Oper
Oper(String name, HMType... args)
Definition: HM2.java:268
com.cliffc.aa.HM.HM2.Let.get_ids
void get_ids()
Definition: HM2.java:155
com.cliffc.aa.HM.HM2.HMVar._str
String _str()
Definition: HM2.java:233
com.cliffc.aa.HM.HM2.Oper.fun
static Oper fun(HMType... args)
Definition: HM2.java:269
com.cliffc.aa.HM.HM2.Oper
Definition: HM2.java:265
com.cliffc.aa.type.TypeMemPtr.STRPTR
static final TypeMemPtr STRPTR
Definition: TypeMemPtr.java:97
com.cliffc.aa.HM.HM2.HMType._str
abstract String _str()
com.cliffc.aa.HM.HM2.hm
static HMType hm(Syntax prog)
Definition: HM2.java:70
com.cliffc.aa.HM.HM2.Lambda.hm
HMType hm(HashSet< HMVar > nongen)
Definition: HM2.java:132
com.cliffc.aa.HM.HM2.Lambda.toString
String toString()
Definition: HM2.java:131
com
com.cliffc.aa.HM.HM2.Ident.Ident
Ident(String name)
Definition: HM2.java:116
com.cliffc.aa.HM.HM2.Oper._args
final HMType[] _args
Definition: HM2.java:267
com.cliffc.aa.type.TypeInt.BOOL
static final TypeInt BOOL
Definition: TypeInt.java:43
com.cliffc.aa.util.SB.toString
String toString()
Definition: SB.java:62
com.cliffc.aa.HM.HM2.Lambda
Definition: HM2.java:127
com.cliffc.aa.type
Definition: Bits.java:1
com.cliffc.aa.type.TypeMemPtr
Definition: TypeMemPtr.java:14
com.cliffc.aa.HM.HM2.HMVar.find
HMType find()
Definition: HM2.java:239
com.cliffc.aa.type.TypeFlt.FLT64
static final TypeFlt FLT64
Definition: TypeFlt.java:38
com.cliffc.aa.HM.HM2.HMVar
Definition: HM2.java:220
com.cliffc.aa.HM.HM2.Apply.toString
String toString()
Definition: HM2.java:160
com.cliffc.aa.HM.HM2.HMType.fresh
HMType fresh(HashSet< HMVar > nongen)
Definition: HM2.java:182