Skip to content

Commit e8eb5df

Browse files
WIP update
1 parent 9f52d79 commit e8eb5df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+1098
-706
lines changed

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ private Node compileCallExpr(AST.CallExpr callExpr) {
656656
if( expr._type == Type.NIL )
657657
throw error("Calling a null function pointer");
658658
if( !(expr instanceof FRefNode) && !expr._type.isa(TypeFunPtr.BOT) )
659-
throw error("Expected a function but got "+expr._type.glb().str());
659+
throw error("Expected a function but got "+expr._type.glb(false).str());
660660
expr.keep(); // Keep while parsing args
661661

662662
Ary<Node> args = new Ary<Node>(Node.class);

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ public Type type() {
3030
Type def = Compiler.TYPES.get(((TypeMemPtr)_type)._obj._name);
3131
return (_type=_type.meet(def));
3232
}
33-
public Type lazyGLB() {
34-
Type t = type();
35-
return t instanceof TypeMemPtr ? t : t.glb();
36-
}
3733

3834
// Forward reference variables (not types) must be BOTTOM and
3935
// distinct from inferred variables

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public enum Phase {
2323
Opto, // Run ideal optimizations
2424
TypeCheck, // Last check for bad programs
2525
LoopTree, // Build a loop tree; break infinite loops
26-
InstSelect, // Convert to target hardware nodes
26+
Select, // Convert to target hardware nodes
2727
Schedule, // Global schedule (code motion) nodes
2828
LocalSched, // Local schedule
2929
RegAlloc, // Register allocation
@@ -40,7 +40,7 @@ public enum Phase {
4040

4141
// ---------------------------
4242
public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L ); }
43-
public CodeGen(String src, TypeInteger arg, long workListSeed ) {
43+
public CodeGen( String src, TypeInteger arg, long workListSeed ) {
4444
CODE = this;
4545
_phase = null;
4646
_callingConv = null;
@@ -57,14 +57,15 @@ public CodeGen(String src, TypeInteger arg, long workListSeed ) {
5757
public CodeGen driver( Phase phase ) { return driver(phase,null,null); }
5858
public CodeGen driver( Phase phase, String cpu, String callingConv ) {
5959
if( _phase==null ) parse();
60-
if( _phase.ordinal() < phase.ordinal() ) opto();
61-
if( _phase.ordinal() < phase.ordinal() ) typeCheck();
62-
if( _phase.ordinal() < phase.ordinal() ) loopTree();
63-
if( _phase.ordinal() < phase.ordinal() && cpu != null ) instSelect(cpu,callingConv);
64-
if( _phase.ordinal() < phase.ordinal() ) GCM();
65-
if( _phase.ordinal() < phase.ordinal() ) localSched();
66-
if( _phase.ordinal() < phase.ordinal() ) regAlloc();
67-
if( _phase.ordinal() < phase.ordinal() ) encode();
60+
int p1 = phase.ordinal();
61+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Opto .ordinal() ) opto();
62+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.TypeCheck .ordinal() ) typeCheck();
63+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LoopTree .ordinal() ) loopTree();
64+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Select .ordinal() && cpu != null ) instSelect(cpu,callingConv);
65+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Schedule .ordinal() ) GCM();
66+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LocalSched.ordinal() ) localSched();
67+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.RegAlloc .ordinal() ) regAlloc();
68+
if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Encoding .ordinal() ) encode();
6869
return this;
6970
}
7071

@@ -123,7 +124,7 @@ public int iDepthFrom(int idepth) {
123124
// Compute "function indices": FIDX.
124125
// Each new request at the same signature gets a new FIDX.
125126
private final HashMap<TypeTuple,Integer> FIDXS = new HashMap<>();
126-
public TypeFunPtr makeFun(TypeTuple sig, Type ret ) {
127+
public TypeFunPtr makeFun( TypeTuple sig, Type ret ) {
127128
Integer i = FIDXS.get(sig);
128129
int fidx = i==null ? 0 : i;
129130
FIDXS.put(sig,fidx+1); // Track count per sig
@@ -229,7 +230,7 @@ public CodeGen loopTree() {
229230
_phase = Phase.LoopTree;
230231
long t0 = System.currentTimeMillis();
231232
// Build the loop tree, fix never-exit loops
232-
_start.buildLoopTree(_stop);
233+
_start.buildLoopTree(_start,_stop);
233234
_tLoopTree = (int)(System.currentTimeMillis() - t0);
234235
return this;
235236
}
@@ -257,7 +258,7 @@ public CodeGen loopTree() {
257258
public CodeGen instSelect( String cpu, String callingConv ) { return instSelect(cpu,callingConv,PORTS); }
258259
public CodeGen instSelect( String cpu, String callingConv, String base ) {
259260
assert _phase.ordinal() == Phase.LoopTree.ordinal();
260-
_phase = Phase.InstSelect;
261+
_phase = Phase.Select;
261262

262263
_callingConv = callingConv;
263264

@@ -288,14 +289,14 @@ public CodeGen instSelect( String cpu, String callingConv, String base ) {
288289
_rpcMask = new RegMask(_mach.rpc());
289290
_retMasks[3] = _rpcMask;
290291

291-
292292
// Convert to machine ops
293293
long t0 = System.currentTimeMillis();
294294
_uid = 1; // All new machine nodes reset numbering
295295
var map = new IdentityHashMap<Node,Node>();
296296
_instSelect( _stop, map );
297297
_stop = ( StopNode)map.get(_stop );
298-
_start = (StartNode)map.get(_start);
298+
StartNode start = (StartNode)map.get(_start);
299+
_start = start==null ? new StartNode(_start) : start;
299300
_instOuts(_stop,visit());
300301
_visit.clear();
301302
_tInsSel = (int)(System.currentTimeMillis() - t0);
@@ -326,8 +327,6 @@ private Node _instSelect( Node n, IdentityHashMap<Node,Node> map ) {
326327
if( x instanceof MachNode mach )
327328
mach.postSelect(this); // Post selection action
328329

329-
// Updates forward edges only.
330-
n._outputs.clear();
331330
return x;
332331
}
333332

@@ -351,7 +350,7 @@ private void _instOuts( Node n, BitSet visit ) {
351350
// Global schedule (code motion) nodes
352351
public CodeGen GCM() { return GCM(false); }
353352
public CodeGen GCM( boolean show) {
354-
assert _phase.ordinal() <= Phase.InstSelect.ordinal();
353+
assert _phase.ordinal() <= Phase.Select.ordinal();
355354
_phase = Phase.Schedule;
356355
long t0 = System.currentTimeMillis();
357356

@@ -451,8 +450,10 @@ public CodeGen exportELF(String fname) throws IOException {
451450
String printCFG() {
452451
if( _cfg==null ) return "no CFG";
453452
SB sb = new SB();
454-
for( CFGNode cfg : _cfg )
455-
IRPrinter.printLine(cfg,sb);
453+
for( CFGNode cfg : _cfg ) {
454+
sb.fix(8,""+cfg._idepth);
455+
IRPrinter.printLine( cfg, sb );
456+
}
456457
return sb.toString();
457458
}
458459

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/ElfFile.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,6 @@ public void export(String fname) throws IOException {
273273
int start_global = num+1; // Add one to skip the final .rela.text local symbol
274274
for( Symbol a: symbols._symbols )
275275
a._index = start_global++;
276-
int bigConIdx = start_global;
277-
start_global += enc._bigCons.size();
278276

279277
// create .text relocations
280278
DataSection text_rela = new DataSection(".rela.text", 4 /* SHT_RELA */);
@@ -298,10 +296,10 @@ public void export(String fname) throws IOException {
298296

299297
// Write relocations for the constant pool
300298
for( Encoding.Relo relo : enc._bigCons.values() ) {
301-
Symbol glob = new Symbol("GLOB$"+bigConIdx, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC);
299+
Symbol glob = new Symbol("CPOOL$"+start_global, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC);
302300
glob._value = relo._target;
303-
glob._size = 1 << relo._t.log_size();
304-
glob._index = bigConIdx++;
301+
glob._size = relo._t.size();
302+
glob._index = start_global++;
305303
symbols.push(glob);
306304
write8(text_rela._contents, relo._opStart+relo._off);
307305
write8(text_rela._contents, ((long)glob._index << 32L) | relo._elf );
@@ -313,6 +311,7 @@ public void export(String fname) throws IOException {
313311
text_rela._info = text._index;
314312
pushSection(text_rela);
315313

314+
// Final .rela.text symbol
316315
Symbol sym = new Symbol(text_rela._name, num++, SYM_BIND_LOCAL, SYM_TYPE_SECTION);
317316
sym._name_pos = text_rela._name_pos;
318317
sym._size = text_rela.size();

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/Encoding.java

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static void padN(int n, BAOS bits) {
9898
}
9999

100100
// Convenience for writing log-N
101-
static void addN(int log, Type t, BAOS bits ) {
101+
static void addN( int log, Type t, BAOS bits ) {
102102
long x = t instanceof TypeInteger ti
103103
? ti.value()
104104
: log==3
@@ -138,14 +138,14 @@ public void jump( CFGNode jmp, CFGNode dst ) {
138138

139139

140140
final HashMap<Node,String> _externals = new HashMap<>();
141-
public Encoding external( Node call, String extern ) {
142-
_externals.put(call,extern);
141+
public Encoding external( Node n, String extern ) {
142+
_externals.put(n,extern);
143143
return this;
144144
}
145145

146146
// Store t as a 32/64 bit constant in the code space; generate RIP-relative
147147
// addressing to load it
148-
public void largeConstant(Node relo, Type t, int off, int elf ) {
148+
public void largeConstant( Node relo, Type t, int off, int elf ) {
149149
assert t.isConstant();
150150
assert (byte)off == off;
151151
assert (byte)elf == elf;
@@ -183,12 +183,10 @@ private void basicBlockLayout() {
183183
Ary<CFGNode> rpo = new Ary<>(CFGNode.class);
184184
rpos.put(_code._start.loop(),rpo);
185185
BitSet visit = _code.visit();
186-
//IdentityHashMap<CFGNode,LoopNode> looptail = new IdentityHashMap<>();
187186
rpo.add(_code._stop);
188187
for( Node n : _code._start._outputs )
189188
if( n instanceof FunNode fun ) {
190189
int x = rpo._len;
191-
//_rpo_cfg2(fun, visit, rpo, looptail);
192190
_rpo_cfg(fun, visit, rpos );
193191
assert rpo.at(x) instanceof ReturnNode;
194192
}
@@ -299,7 +297,7 @@ private static boolean shouldInvert(CFGNode t, CFGNode f, int bld) {
299297
private static boolean forwardsEmptyScan( CFGNode c, int bld ) {
300298
if( c.nOuts()!=1 || c.loopDepth()!=bld ) return false;
301299
return c.uctrl() instanceof RegionNode cfg &&
302-
(cfg instanceof LoopNode || forwardsEmptyScan(cfg,bld));
300+
((cfg instanceof LoopNode && cfg._ltree==c._ltree) || forwardsEmptyScan(cfg,bld));
303301
}
304302

305303
// Is the CFG from "next" to the end empty? This means jumping to "next"
@@ -387,6 +385,23 @@ private void compactShortForm() {
387385
}
388386

389387

388+
// Go again, inserting padding on function headers. Since no
389+
// short-jumps span function headers, the padding will not make any
390+
// short jumps fail.
391+
for( int i=0; i<len; i++ ) {
392+
CFGNode bb = _code._cfg.at(i);
393+
// Functions pad to align 16
394+
if( bb instanceof FunNode ) {
395+
int newStart = _opStart[bb._nid]+slide;
396+
slide += (newStart+15 & -16)-newStart;
397+
}
398+
_opStart[bb._nid] += slide;
399+
for( Node n : bb._outputs )
400+
if( n instanceof MachNode && !(n instanceof CFGNode) )
401+
_opStart[n._nid] += slide;
402+
}
403+
404+
390405
// Copy/slide the bits to make space for all the longer branches
391406
int grow = _opStart[_code._cfg.at(len-1)._nid] - oldStarts[len-1];
392407
if( grow > 0 ) { // If no short-form ops, nothing to do here
@@ -422,47 +437,90 @@ void patchLocalRelocations() {
422437
void writeConstantPool( BAOS bits, boolean patch ) {
423438
padN(16,bits);
424439

440+
// radix sort the big constants by alignment
441+
Ary<Relo>[] raligns = new Ary[5];
442+
for( Node op : _bigCons.keySet() ) {
443+
Relo relo = _bigCons.get(op);
444+
int align = relo._t.alignment();
445+
Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>(Relo.class)) : raligns[align];
446+
relos.add(relo);
447+
}
448+
449+
450+
// Types can be used more than once; collapse the dups
425451
HashMap<Type,Integer> targets = new HashMap<>();
426452

427-
// By log size
428-
for( int log = 3; log >= 0; log-- ) {
429-
// Write the 8-byte constants
430-
for( Node op : _bigCons.keySet() ) {
431-
Relo relo = _bigCons.get(op);
432-
if( relo._t.log_size()==log ) {
433-
// Map from relo to constant start and patch
434-
Integer target = targets.get(relo._t);
435-
if( target==null ) {
436-
targets.put(relo._t,target = bits.size());
437-
// Put constant into code space.
438-
if( relo._t instanceof TypeTuple tt ) // Constant tuples put all entries
439-
for( Type tx : tt._types )
440-
addN(log,tx,bits);
441-
else
442-
addN(log,relo._t,bits);
453+
// By alignment
454+
for( int align = 4; align >= 0; align-- ) {
455+
Ary<Relo> relos = raligns[align];
456+
if( relos == null ) continue;
457+
for( Relo relo : relos ) {
458+
// Map from relo to constant start and patch
459+
Integer target = targets.get(relo._t);
460+
if( target==null ) {
461+
targets.put(relo._t,target = bits.size());
462+
// Write constant into constant pool
463+
switch( relo._t ) {
464+
case TypeTuple tt -> cpool(align,bits,tt);
465+
case TypeStruct ts -> cpool(bits,ts);
466+
// Simple primitive (e.g. larger int, float)
467+
default -> addN(align,relo._t,bits);
443468
}
444-
relo._target = target;
445-
relo._opStart= _opStart[op._nid];
446-
// Go ahead and locally patch in-memory
447-
if( patch )
448-
((RIPRelSize)op).patch(this, relo._opStart, _opLen[op._nid], relo._target - relo._opStart);
449469
}
470+
// Record target address and opcode start
471+
relo._target = target;
472+
relo._opStart= _opStart[relo._op._nid];
473+
// Go ahead and locally patch in-memory
474+
if( patch )
475+
((RIPRelSize)relo._op).patch(this, relo._opStart, _opLen[relo._op._nid], relo._target - relo._opStart);
450476
}
451477
}
452478
}
453479

480+
// Constant tuples put all entries at same alignment
481+
private void cpool(int align, BAOS bits, TypeTuple tt) {
482+
for( Type tx : tt._types )
483+
addN(align,tx,bits);
484+
}
485+
486+
// Structs use internal field layout
487+
private void cpool( BAOS bits, TypeStruct ts ) {
488+
// Field order by offset
489+
int[] layout = ts.layout();
490+
int off=0; // offset in the struct
491+
for( int fn=0; fn<ts._fields.length; fn++ ) {
492+
Field f = ts._fields[layout[fn]];
493+
int foff = ts. offset(layout[fn]);
494+
// Pad up to field
495+
while( off < foff ) { bits.write(0); off++; };
496+
// Constant array fields are special
497+
// FIXME Dibyendu
498+
// if( f._fname=="[]" ) { // Must be a constant array
499+
// ts._con.write(bits); // Write the constant array bits
500+
// off += ts._con.len();
501+
// } else {
502+
// int log = f._type.log_size();
503+
// if( f._fname=="#" ) addN(log,ts._con.len(),bits); // Must be a constant array
504+
// else addN(log,f._type ,bits);
505+
// off += 1<<log;
506+
// }
507+
}
508+
}
509+
454510

455511
// A series of libc/external calls that Simple can link against in a JIT.
456512
// Since no runtime in the JVM process, using magic numbers for the CPU
457513
// emulators to pick up on.
458-
public static int SENTINAL_CALLOC = -4;
514+
public static int SENTINEL_CALLOC = -4;
515+
public static int SENTINEL_WRITE = -8;
459516

460517
void patchGlobalRelocations() {
461518
for( Node src : _externals.keySet() ) {
462519
int start = _opStart[src._nid];
463520
String dst = _externals.get(src);
464521
int target = switch( dst ) {
465-
case "calloc" -> SENTINAL_CALLOC;
522+
case "calloc" -> SENTINEL_CALLOC;
523+
case "write" -> SENTINEL_WRITE ;
466524
default -> throw Utils.TODO();
467525
};
468526
((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start);

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/GlobalCodeMotion.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public static void buildCFG( CodeGen code ) {
3232

3333
// Post-Order of CFG
3434
private static void _rpo_cfg(CFGNode def, Node use, BitSet visit, Ary<CFGNode> rpo) {
35-
if( use instanceof CallNode call ) call.unlink_all();
3635
if( !(use instanceof CFGNode cfg) || visit.get(cfg._nid) )
3736
return; // Been there, done that
3837
if( def instanceof ReturnNode && use instanceof CallEndNode )
@@ -178,14 +177,22 @@ private static void breadth(Node stop, Node[] ns, CFGNode[] late) {
178177
}
179178

180179
// Walk all inputs and put on worklist, as their last-use might now be done
181-
for( Node def : n._inputs )
182-
if( def!=null && late[def._nid]==null ) {
180+
for( Node def : n._inputs ) {
181+
if( def!=null && late[def._nid]==null )
183182
work.push(def);
184-
// if the def has a load use, maybe the load can fire
183+
// if the def has a load use, maybe the load can fire
184+
if( def!=null )
185185
for( Node out : def._outputs )
186186
if( out instanceof MemOpNode ld && ld._isLoad && late[ld._nid]==null )
187187
work.push(ld);
188+
}
189+
190+
if( n instanceof LoopNode loop ) {
191+
for( Node phi : loop._outputs ) {
192+
if( phi instanceof PhiNode && late[phi._nid]==null )
193+
work.push(phi);
188194
}
195+
}
189196
}
190197
}
191198

@@ -274,7 +281,7 @@ private static CFGNode find_anti_dep(CFGNode lca, MemOpNode load, CFGNode early,
274281
for( Node mem : load.mem()._outputs ) {
275282
switch( mem ) {
276283
case MemOpNode st:
277-
if( !st._isLoad ) {
284+
if( !st._isLoad && load._alias == st._alias ) {
278285
assert late[mem._nid] != null;
279286
lca = anti_dep( load, late[mem._nid], mem.cfg0(), lca, st );
280287
}

0 commit comments

Comments
 (0)