Skip to content

Commit 787840a

Browse files
Sync with final ch21
1 parent 044886d commit 787840a

28 files changed

+423
-300
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public class IterPeeps {
4949

5050
public IterPeeps( long seed ) { _work = new WorkList<>(seed); }
5151

52-
@SuppressWarnings("unchecked")
5352
public <N extends Node> N add( N n ) { return (N)_work.push(n); }
5453

5554
public void addAll( Ary<Node> ary ) { _work.addAll(ary); }
@@ -127,7 +126,6 @@ private boolean progressOnList(CodeGen code) {
127126
* Classic WorkList, with a fast add/remove, dup removal, random pull.
128127
* The Node's nid is used to check membership in the worklist.
129128
*/
130-
@SuppressWarnings("unchecked")
131129
public static class WorkList<E extends Node> {
132130

133131
private Node[] _es;

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

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,21 @@ else if( Double.isInfinite(s) ) {
2929
public SB p( int s ) { _sb.append(s); return this; }
3030
public SB p( long s ) { _sb.append(s); return this; }
3131
public SB p( boolean s) { _sb.append(s); return this; }
32-
// 1 byte, 2 hex digits, 8 bits
33-
public SB hex1(int s) {
34-
int digit = (s>>4) & 0xf;
35-
_sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
36-
digit = s & 0xf;
37-
_sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
32+
// 4 hex digits
33+
public SB hex4(int s) {
34+
assert (s>>4*4)==0; // Fits in 16 bits
35+
for( int i=0; i<4; i++ ) {
36+
int digit = (s>>((3-i)*4)) & 0xf;
37+
_sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
38+
}
3839
return this;
3940
}
40-
// 2 bytes, 4 hex digits, 16 bits, Big Endian
41-
public SB hex2(int s) { return hex1(s>> 8).hex1(s); }
42-
// 4 bytes, 8 hex digits, 32 bits, Big Endian
43-
public SB hex4(int s) { return hex2(s>>16).hex2(s); }
44-
// 8 bytes, 16 hex digits, 64 bits, Big Endian
45-
public SB hex8(long s) { return hex4((int)(s>>32)).hex4((int)s); }
46-
4741
// Fixed width field
4842
public SB fix( int sz, String s ) {
4943
for( int i=0; i<sz; i++ )
5044
_sb.append( i < s.length() ? s.charAt(i) : ' ');
5145
return this;
5246
}
53-
public char at(int idx ) { return _sb.charAt(idx); }
5447

5548
// Not spelled "p" on purpose: too easy to accidentally say "p(1.0)" and
5649
// suddenly call the autoboxed version.
@@ -90,8 +83,6 @@ public boolean was_nl() {
9083
//
9184
public SB unchar() { return unchar(1); }
9285
public SB unchar(int x) { _sb.setLength(_sb.length()-x); return this; }
93-
public SB setLen(int len) { _sb.setLength(len); return this; }
94-
public String subString(int start, int end ) { return _sb.substring(start,end); }
9586

9687
public SB clear() { _sb.setLength(0); return this; }
9788
public int len() { return _sb.length(); }

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/AddNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public Node idealize () {
9696
// If lhs.in(2) is not a constant, we add ourselves as a dependency
9797
// because if it later became a constant then we could make this
9898
// transformation.
99-
if( lhs.in(2).addDep(this)._type.isConstant() && rhs._type.isConstant() )
99+
if( addDep(lhs.in(2))._type.isConstant() && rhs._type.isConstant() )
100100
return new AddNode(lhs.in(1),new AddNode(lhs.in(2),rhs).peephole());
101101

102102

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CFGNode.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public CFGNode uctrl() {
5353

5454
// Used by the encoding / final BB layout
5555
public CFGNode uctrlSkipEmpty() {
56-
CFGNode x = this, y=null;
56+
CFGNode x = this, y;
5757
while( x.nOuts() == 1 && (y=x.uctrl())!=null ) // Skip empty blocks
5858
x = y;
5959
return x;
@@ -80,8 +80,8 @@ public CFGNode _idom(CFGNode rhs, Node dep) {
8080
CFGNode lhs = this;
8181
while( lhs != rhs ) {
8282
var comp = lhs.idepth() - rhs.idepth();
83-
if( comp >= 0 ) lhs = ((CFGNode)lhs.addDep(dep)).idom();
84-
if( comp <= 0 ) rhs = ((CFGNode)rhs.addDep(dep)).idom();
83+
if( comp >= 0 ) lhs = (dep==null ? lhs : dep.addDep(lhs)).idom();
84+
if( comp <= 0 ) rhs = (dep==null ? rhs : dep.addDep(rhs)).idom();
8585
}
8686
return lhs;
8787
}
@@ -102,7 +102,7 @@ public FunNode fun() {
102102
public LoopNode loop() { return _ltree._head; }
103103
public int loopDepth() { return _ltree==null ? 0 : _ltree.depth(); }
104104

105-
LoopTree _ltree;
105+
public LoopTree _ltree;
106106
public int _pre; // Pre-order numbers for loop tree finding
107107
static class LoopTree {
108108
LoopTree _par;

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CProjNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public Node idealize() {
4444
}
4545

4646
// Flip a negating if-test, to remove the not
47-
if( ctrl() instanceof IfNode iff && iff.pred().addDep(this) instanceof NotNode not )
47+
if( ctrl() instanceof IfNode iff && addDep(iff.pred()) instanceof NotNode not )
4848
return new CProjNode(new IfNode(iff.ctrl(),not.in(1)).peephole(),1-_idx,_idx==0 ? "False" : "True");
4949

5050
// Copy of some other input
@@ -58,7 +58,7 @@ public void invert() {
5858
}
5959

6060
@Override
61-
boolean eq( Node n ) { return _idx == ((CProjNode)n)._idx; }
61+
public boolean eq( Node n ) { return _idx == ((CProjNode)n)._idx; }
6262

6363
@Override
6464
int hash() { return _idx; }

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CallEndNode.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.compilerprogramming.ezlang.compiler.nodes;
22

33
import com.compilerprogramming.ezlang.compiler.Compiler;
4+
import com.compilerprogramming.ezlang.compiler.SB;
45
import com.compilerprogramming.ezlang.compiler.codegen.CodeGen;
6+
import com.compilerprogramming.ezlang.compiler.codegen.Encoding;
7+
import com.compilerprogramming.ezlang.compiler.codegen.RegMask;
8+
import com.compilerprogramming.ezlang.compiler.codegen.RegMaskRW;
59
import com.compilerprogramming.ezlang.compiler.sontypes.*;
610
import java.util.BitSet;
711

@@ -38,7 +42,7 @@ public SONType compute() {
3842
return SONTypeTuple.RET.dual();
3943
SONType ret = SONType.BOTTOM;
4044
SONTypeMem mem = SONTypeMem.BOT;
41-
if( call.fptr().addDep(this)._type instanceof SONTypeFunPtr tfp ) {
45+
if( addDep(call.fptr())._type instanceof SONTypeFunPtr tfp ) {
4246
ret = tfp.ret();
4347
// Here, if I can figure out I've found *all* callers, then I can meet
4448
// across the linked returns and join with the function return type.
@@ -84,10 +88,10 @@ public Node idealize() {
8488
return this;
8589
}
8690
} else {
87-
fun.addDep(this);
91+
addDep(fun);
8892
}
8993
} else { // Function ptr has multiple users (so maybe multiple call sites)
90-
fptr.addDep(this);
94+
addDep(fptr);
9195
}
9296
}
9397

@@ -97,4 +101,34 @@ public Node idealize() {
97101
@Override public Node pcopy(int idx) {
98102
return _folding ? in(1).in(idx) : null;
99103
}
104+
105+
// ------------
106+
// MachNode specifics, shared across all CPUs
107+
public int _xslot;
108+
private RegMask _retMask;
109+
private RegMask _kills;
110+
public void cacheRegs(CodeGen code) {
111+
// Return mask depends on TFP (either GPR or FPR)
112+
_retMask = code._mach.retMask(call().tfp());
113+
// Kill mask is all caller-saves, and any mirror stack slots for args
114+
// in registers.
115+
RegMaskRW kills = code._callerSave.copy();
116+
// Start of stack slots
117+
int maxReg = code._mach.regs().length;
118+
// Incoming function arg slots, all low numbered in the RA
119+
int fslot = fun()._maxArgSlot;
120+
// Killed slots for this calls outgoing args
121+
int xslot = code._mach.maxArgSlot(call().tfp());
122+
_xslot = (maxReg+fslot)+xslot;
123+
for( int i=0; i<xslot; i++ )
124+
kills.set((maxReg+fslot)+i);
125+
_kills = kills;
126+
}
127+
public String op() { return "cend"; }
128+
public RegMask regmap(int i) { return null; }
129+
public RegMask outregmap() { return null; }
130+
public RegMask outregmap(int idx) { return idx==2 ? _retMask : null; }
131+
public RegMask killmap() { return _kills; }
132+
public void encoding( Encoding enc ) { }
133+
public void asm(CodeGen code, SB sb) { }
100134
}

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/CastNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public Node idealize() {
4646
}
4747

4848
@Override
49-
boolean eq(Node n) {
49+
public boolean eq(Node n) {
5050
CastNode cast = (CastNode)n; // Contract
5151
return _t==cast._t;
5252
}

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/ConstantNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public ConstantNode( SONType type ) {
2626
_con = _type = type;
2727
}
2828
public ConstantNode( Node con, SONType t ) { super(con); _con = t; }
29-
public ConstantNode( ConstantNode con ) { super(con); _con = con._type; }
29+
public ConstantNode( ConstantNode con ) { this(con,con._type); }
3030

3131
public static Node make( SONType type ) {
3232
if( type== SONType. CONTROL ) return new CtrlNode();
@@ -44,7 +44,7 @@ public static Node make( SONType type ) {
4444
public StringBuilder _print1(StringBuilder sb, BitSet visited) {
4545
if( _con instanceof SONTypeFunPtr tfp && tfp.isConstant() ) {
4646
FunNode fun = CodeGen.CODE.link(tfp);
47-
if( fun._name != null )
47+
if( fun!=null && fun._name != null )
4848
return sb.append("{ ").append(fun._name).append("}");
4949
}
5050
return sb.append(_con==null ? "---" : _con.print(new SB()));

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/FunNode.java

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.compilerprogramming.ezlang.compiler.nodes;
22

33
import com.compilerprogramming.ezlang.compiler.*;
4+
import com.compilerprogramming.ezlang.compiler.codegen.CodeGen;
5+
import com.compilerprogramming.ezlang.compiler.codegen.Encoding;
6+
import com.compilerprogramming.ezlang.compiler.codegen.RegMask;
47
import com.compilerprogramming.ezlang.compiler.sontypes.SONType;
58
import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeFunPtr;
69
import com.compilerprogramming.ezlang.compiler.sontypes.SONTypeTuple;
@@ -164,36 +167,51 @@ private static boolean walkDown( Node n, BitSet cfgs, BitSet body, BitSet visit
164167
}
165168

166169

167-
// | CALLER |
168-
// | |
169-
// | argN+1 | // slot 1, callER +32
170-
// | argN | // slot 0, callER +24
171-
// +--------+ // OLD FRAME
172-
// | PAD | // Alignment pad +16
173-
// | callee | // slot 3, callEE + 8
174-
// | callee | // slot 2, callEE + 0
175-
// +--------+ // RSP
176-
177-
// TODO: lower this field into a generic FunMachNode.
178-
// Replace all FunXXX variants with FunMachNode.
170+
// ------------
171+
// MachNode specifics, shared across all CPUs
179172

180173
// Function may call other functions? X86 requires 16b aligned SP on
181174
// outbound calls, but not leaf. Set during an unrelated RA scan.
182175
public boolean _hasCalls;
183176

184-
// Max observed spill slot, set during RA postcolor
185-
public short _maxSlot = -1;
186-
// Max argument slot, set during early Encoding.
187-
public short _maxArgSlot = -1;
188-
// Frame adjust, including padding, st during early Encoding
189-
public short _frameAdjust;
177+
// Maximum incoming argument slot, based on function type
178+
public int _maxArgSlot;
179+
180+
// Frame adjust, including padding, set during early Encoding
181+
public int _frameAdjust;
190182

183+
public String op() { return _frameAdjust==0 ? "entry" : "subi"; }
184+
public void postSelect(CodeGen code) {
185+
code.link(this);
186+
// Max slot seen past space reserved for incoming arguments
187+
_maxArgSlot = code._mach.maxArgSlot(sig());
188+
}
189+
public RegMask regmap(int i) { return null; }
190+
public RegMask outregmap() { return null; }
191+
public void encoding( Encoding enc ) { throw Utils.TODO(); }
192+
public void asm(CodeGen code, SB sb) {
193+
if( _frameAdjust!=0 )
194+
sb.p("rsp -= #").p(_frameAdjust);
195+
}
191196

192-
// Convert a stack slot, based on the frame, into an offset. Stack layout
193-
// is the same for all CPUs; X86 will pre-spill the RPC.
194-
public final int computeStackSlot(int slotN) {
195-
return slotN < _maxArgSlot
196-
? slotN + _frameAdjust
197-
: slotN - _maxArgSlot;
197+
public void computeFrameAdjust(CodeGen code, int maxReg) {
198+
// Max slot seen, or 0.
199+
int maxSlot = Math.max(maxReg - code._mach.regs().length,_maxArgSlot);
200+
// Frame adjust before rounding, can be negative for no spills
201+
int size = maxSlot - _maxArgSlot;
202+
_frameAdjust = size*8;
198203
}
204+
205+
// Given a high register number and during encoding compute the stack
206+
// pointer offset. Pre-RA we lack the fun._frameAdjust. We also need a
207+
// FunNode.
208+
public int computeStackOffset(CodeGen code, int reg) {
209+
String[] regs = code._mach.regs();
210+
int stackSlot = reg - regs.length;
211+
int slotRotate = stackSlot < _maxArgSlot
212+
? stackSlot + (_frameAdjust>>3)
213+
: stackSlot - _maxArgSlot;
214+
return slotRotate*8;
215+
}
216+
199217
}

seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/nodes/IfNode.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ public IfNode(Node ctrl, Node pred) {
2020
@Override
2121
public StringBuilder _print1(StringBuilder sb, BitSet visited) {
2222
sb.append("if( ");
23-
return in(1)._print0(sb, visited).append(" )");
23+
if( in(1)==null ) sb.append("never");
24+
else in(1)._print0(sb, visited);
25+
return sb.append(" )");
2426
}
2527

2628
public Node ctrl() { return in(0); }
@@ -57,19 +59,19 @@ public Node idealize() {
5759
// test on either the true or false branch, that side wins.
5860
if( !pred()._type.isHighOrConst() )
5961
for( CFGNode dom = idom(), prior=this; dom!=null; prior = dom, dom = dom.idom() )
60-
if( dom.addDep(this) instanceof IfNode iff && iff.pred().addDep(this)==pred() && prior instanceof CProjNode prj ) {
62+
if( addDep(dom) instanceof IfNode iff && addDep(iff.pred())==pred() && prior instanceof CProjNode prj ) {
6163
setDef(1,con( prj._idx==0 ? 1 : 0 ));
6264
return this;
6365
}
6466
return null;
6567
}
6668

67-
// MachNode variants need to support this and invert the conditional test.
69+
// MachNode variants need to support this and negate the conditional test.
6870
// The following CProjs will be inverted by the caller.
69-
public void invert() { throw Utils.TODO(); }
71+
public void negate() { throw Utils.TODO(); }
7072

7173
// Negate the sense of a test
72-
public static String invert( String bop ) {
74+
public static String negate( String bop ) {
7375
return switch( bop ) {
7476
case "<" -> ">=";
7577
case "<=" -> ">" ;

0 commit comments

Comments
 (0)