From 6afee244d59fc31ccdfa4e46dcc29c76b20e6e60 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sun, 4 May 2025 13:25:38 -0700 Subject: Unwind back to 8b int/ptr. GCM bug: unlinking a call shuffles StartNode output order, might miss a later unlink. RA bug spilling a constant to 2 different fixed stack slots. Turn off broken store-of-sign-extend check. --- .../simple/codegen/GlobalCodeMotion.java | 14 +++++- .../com/seaofnodes/simple/codegen/RegAlloc.java | 13 ++++-- .../main/java/com/seaofnodes/simple/node/Node.java | 2 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 20 ++++---- .../simple/node/cpus/riscv/MemOpRISC.java | 12 +++-- .../main/java/com/seaofnodes/simple/sys/sys.smp | 14 +++++- .../com/seaofnodes/simple/type/TypeMemPtr.java | 2 +- .../java/com/seaofnodes/simple/Chapter13Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter21Test.java | 53 +++++++++++---------- .../java/com/seaofnodes/simple/Chapter22Test.java | 54 +++++++++++----------- 10 files changed, 103 insertions(+), 83 deletions(-) (limited to 'chapter22/src') diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java index e904dc66..c05cfe2e 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java @@ -13,6 +13,19 @@ public abstract class GlobalCodeMotion { // Node.use(0) is always a block tail (either IfNode or head of the // following block). There are no unreachable infinite loops. public static void buildCFG( CodeGen code ) { + // Unlink all linked calls. This can remove RPC constants which + // shuffled the StartNode outputs so requires a while loop. + boolean done=false; + while(!done) { + done = true; + for( Node use : code._start._outputs ) + if( use instanceof FunNode fun ) + for( Node c : fun._inputs ) + if( c instanceof CallNode call ) + { call.unlink_all(); done=false; } + } + + Ary rpo = new Ary<>(CFGNode.class); _rpo_cfg(null, code._start, code.visit(), rpo); // Reverse in-place @@ -32,7 +45,6 @@ public abstract class GlobalCodeMotion { // Post-Order of CFG private static void _rpo_cfg(CFGNode def, Node use, BitSet visit, Ary rpo) { - if( use instanceof CallNode call ) call.unlink_all(); if( !(use instanceof CFGNode cfg) || visit.get(cfg._nid) ) return; // Been there, done that if( def instanceof ReturnNode && use instanceof CallEndNode ) diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java index e1051fc6..e4a48750 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java @@ -285,7 +285,7 @@ public class RegAlloc { // Split by class for( RegMask rmask : rclass ) { - Node split = makeSplit(def,"popular",round,lrg); + Node split = makeSplit(def,"popular",round,lrg,rmask); split.insertAfter( def ); if( split.nIns()>1 ) split.setDef(1,def); // all uses by class to split @@ -491,15 +491,17 @@ public class RegAlloc { Node def = n.in(i); // Effective block for use CFGNode cfg = n instanceof PhiNode phi ? phi.region().cfg(i) : n.cfg0(); + // Use-side RegMask, if available + RegMask umask = n instanceof MachNode mach ? mach.regmap(i) : null; // Def is a split ? if( skip && def instanceof SplitNode ) { - boolean singleReg = n instanceof MachNode mach && mach.regmap(i).size1(); + boolean singleReg = umask!=null && umask.size1(); // Same block, multiple registers, split is only used by n, // assume this is good enough and do not split again. if( cfg==def.cfg0() && def.nOuts()==1 && !singleReg ) return; } - makeSplit(def,kind,round,lrg).insertBefore(n, i); + makeSplit(def,kind,round,lrg,umask).insertBefore(n, i); // Skip split-of-split same block if( skip && def instanceof SplitNode && cfg==def.cfg0() ) n.in(i).setDefOrdered(1,def.in(1)); @@ -526,8 +528,9 @@ public class RegAlloc { } } - private Node makeSplit( Node def, String kind, byte round, LRG lrg ) { - Node split = def instanceof MachNode mach && mach.isClone() + private Node makeSplit( Node def, String kind, byte round, LRG lrg, RegMask umask ) { + // Clone simple constants if possible + Node split = def instanceof MachNode mach && mach.isClone() && (umask==null || mach.outregmap().overlap(umask)) ? mach.copy() : _code._mach.split(kind,round,lrg); _lrgs.put(split,lrg); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java index 18a8bc14..39010f3d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java @@ -43,7 +43,7 @@ public abstract class Node implements Cloneable { * walked in either direction. These outputs are typically used for * efficient optimizations but otherwise have no semantics meaning. */ - public Ary _outputs; + public Ary _outputs; /** diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java index 87190f37..0beef65c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -84,18 +84,14 @@ public class StoreNode extends MemOpNode { } } - if( val() instanceof SarNode shr && - shr.in(1) instanceof ShlNode shl && - shr.in(2)._type.isConstant() && - shl.in(2)._type.isConstant() ) { - - ConstantNode shr_s = (ConstantNode)(shr.in(2)); - ConstantNode shl_s = (ConstantNode)(shl.in(2)); - - if( shl_s._type == shr_s._type ) - //return setDef(3, shl.in(1)); - throw Utils.TODO(); - } + // TODO: Needs more love: the shift amount depends on the store size + //if( val() instanceof SarNode shr && + // shr.in(1) instanceof ShlNode shl && + // shr.in(2)._type.isConstant() && + // shl.in(2)._type.isConstant() ) { + // if( shl.in(2)._type == shr.in(2)._type ) + // return setDef(3, shl.in(1)); + //} return null; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java index 7f9b582a..8b84a2b9 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -35,8 +35,9 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { if(this instanceof StoreRISC) { if( _declaredType == TypeInteger. I8 || _declaredType == TypeInteger.U8 || _declaredType == TypeInteger.BOOL) func3=0; // SB if( _declaredType == TypeInteger.I16 || _declaredType == TypeInteger.U16 ) func3=1; // SH - if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 || _declaredType instanceof TypeMemPtr) func3=2; // SW - if( _declaredType == TypeInteger.BOT ) func3=3; // SD + if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 ) func3=2; // SW + if( _declaredType instanceof TypeMemPtr) func3=3; // SD + if( _declaredType == TypeInteger.BOT ) func3=3; // SD if( func3 == -1 ) throw Utils.TODO(); return func3; } @@ -50,9 +51,10 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { if( _declaredType == TypeInteger.U32 ) func3=6; // LWU // float - if(_declaredType == TypeFloat.F32) func3 = 2; // fLW fSW - if(_declaredType == TypeFloat.F64) func3 = 3; // fLD fSD - if( _declaredType instanceof TypeMemPtr) func3 = 6; // 4 byte pointers(pick lw/u) + if( _declaredType == TypeFloat.F32) func3 = 2; // fLW fSW + if( _declaredType == TypeFloat.F64) func3 = 3; // fLD fSD + + if( _declaredType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) if( func3 == -1 ) throw Utils.TODO(); return func3; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp index 64c1b93e..6b12ba20 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp +++ b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp @@ -3,8 +3,18 @@ // top-level default import struct sys { // libc bindings + /** https://www.man7.org/linux/man-pages/man2/.2.html */ struct libc { - /** https://www.man7.org/linux/man-pages/man2/write.2.html */ - { i32 u8[~] i32 -> i32 } write = "C"; + // fd buf len -> len + { i32 u8[~] i32 -> i32 } write = "C"; + // addr len prot flags fd off -> void* + { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; + // mmap flags + i32 PROT_EXEC = 4; + i32 PROT_READ = 1; + i32 PROT_WRITE= 2; + i32 PROT_NONE = 0; + i32 MAP_PRIVATE = 2; + i32 MAP_ANON = 32; }; }; diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java index 8c038f8e..78605e81 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java @@ -82,7 +82,7 @@ public class TypeMemPtr extends TypeNil { // Is forward-reference @Override public boolean isFRef() { return _obj.isFRef(); } - @Override public int log_size() { return 2; } // (1<<3)==4-byte pointers + @Override public int log_size() { return 3; } // (1<<3)==8-byte pointers @Override int hash() { return _obj.hashCode() ^ super.hash() ^ (_one ? 2048 : 0); } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter13Test.java index 4f5c30c1..a4644917 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -33,7 +33,7 @@ while( arg ) { return head.next.i; """); try { code.parse().opto().typeCheck(); fail(); } - catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } + catch( Exception e ) { assertEquals("Might be null accessing 'next'",e.getMessage()); } } @Test diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java index 4210fc56..96e6c5ff 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -165,49 +165,48 @@ public class Chapter21Test { @Test public void testPerson() throws IOException { String person = "6\n"; - // Todo: Need to fix it(switch to 4 byte pointers) TestC.run("person", person, 0); // Memory layout starting at PS: int ps = 1<<16; // Person array pointer starts at heap start // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8 - // P0 = { age } // sizeof=4 - int p0 = ps+4*4+0*4; - // P1 = { age } // sizeof=4 - int p1 = ps+4*4+1*4; - // P2 = { age } // sizeof=4 - int p2 = ps+4*4+2*4; + // P0 = { age } // sizeof=8 + int p0 = ps+4*8+0*8; + // P1 = { age } // sizeof=8 + int p1 = ps+4*8+1*8; + // P2 = { age } // sizeof=8 + int p2 = ps+4*8+2*8; EvalRisc5 R5 = TestRisc5.build("person", ps, 0, false); R5.regs[riscv.A1] = 1; // Index 1 - R5.st4(ps,3); // Length - R5.st4(ps+1*4,p0); - R5.st4(ps+2*4,p1); - R5.st4(ps+3*4,p2); - R5.st4(p0, 5); // age= 5 - R5.st4(p1,17); // age=17 - R5.st4(p2,60); // age=60 + R5.st8(ps,3); // Length + R5.st8(ps+1*8,p0); + R5.st8(ps+2*8,p1); + R5.st8(ps+3*8,p2); + R5.st8(p0, 5); // age= 5 + R5.st8(p1,17); // age=17 + R5.st8(p2,60); // age=60 int trap = R5.step(100); assertEquals(0,trap); - assertEquals( 5+0,R5.ld4s(p0)); - assertEquals(17+1,R5.ld4s(p1)); - assertEquals(60+0,R5.ld4s(p2)); + assertEquals( 5+0,R5.ld8(p0)); + assertEquals(17+1,R5.ld8(p1)); + assertEquals(60+0,R5.ld8(p2)); EvalArm64 A5 = TestArm64.build("person", ps, 0, false); A5.regs[arm.X1] = 1; // Index 1 - A5.st4(ps, 3); - A5.st4(ps+1*4,p0); - A5.st4(ps+2*4,p1); - A5.st4(ps+3*4,p2); - A5.st4(p0, 5); // age= 5 - A5.st4(p1,17); // age=17 - A5.st4(p2,60); // age=60 + A5.st8(ps, 3); + A5.st8(ps+1*8,p0); + A5.st8(ps+2*8,p1); + A5.st8(ps+3*8,p2); + A5.st8(p0, 5); // age= 5 + A5.st8(p1,17); // age=17 + A5.st8(p2,60); // age=60 int trap_arm = A5.step(100); assertEquals(0,trap_arm); - assertEquals( 5+0, A5.ld4s(p0)); - assertEquals(17+1, A5.ld4s(p1)); - assertEquals(60+0, A5.ld4s(p2)); + assertEquals( 5+0, A5.ld8(p0)); + assertEquals(17+1, A5.ld8(p1)); + assertEquals(60+0, A5.ld8(p2)); } @Test public void testArgCount() throws IOException { diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java index 4932ba3f..3f86e8ac 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -32,52 +32,50 @@ public class Chapter22Test { } - // Int now is changed to 4 bytes. @Test public void testPerson() throws IOException { String person = "6\n"; - // Todo: need to fix it and switch to 4 byte pointers TestC.run("person", person, 0); // Memory layout starting at PS: int ps = 1<<16; // Person array pointer starts at heap start // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8 - // P0 = { age } // sizeof=4 - int p0 = ps+4*4+0*4; - // P1 = { age } // sizeof=4 - int p1 = ps+4*4+1*4; - // P2 = { age } // sizeof=4 - int p2 = ps+4*4+2*4; + // P0 = { age } // sizeof=8 + int p0 = ps+4*8+0*8; + // P1 = { age } // sizeof=8 + int p1 = ps+4*8+1*8; + // P2 = { age } // sizeof=8 + int p2 = ps+4*8+2*8; EvalRisc5 R5 = TestRisc5.build("person", ps, 0, false); R5.regs[riscv.A1] = 1; // Index 1 - R5.st4(ps,3); // Length - R5.st4(ps+1*4,p0); - R5.st4(ps+2*4,p1); - R5.st4(ps+3*4,p2); - R5.st4(p0, 5); // age= 5 - R5.st4(p1,17); // age=17 - R5.st4(p2,60); // age=60 + R5.st8(ps,3); // Length + R5.st8(ps+1*8,p0); + R5.st8(ps+2*8,p1); + R5.st8(ps+3*8,p2); + R5.st8(p0, 5); // age= 5 + R5.st8(p1,17); // age=17 + R5.st8(p2,60); // age=60 int trap = R5.step(100); assertEquals(0,trap); - assertEquals( 5+0,R5.ld4s(p0)); - assertEquals(17+1,R5.ld4s(p1)); - assertEquals(60+0,R5.ld4s(p2)); + assertEquals( 5+0,R5.ld8(p0)); + assertEquals(17+1,R5.ld8(p1)); + assertEquals(60+0,R5.ld8(p2)); EvalArm64 A5 = TestArm64.build("person", ps, 0, false); A5.regs[arm.X1] = 1; // Index 1 - A5.st4(ps, 3); - A5.st4(ps+1*4,p0); - A5.st4(ps+2*4,p1); - A5.st4(ps+3*4,p2); - A5.st4(p0, 5); // age= 5 - A5.st4(p1,17); // age=17 - A5.st4(p2,60); // age=60 + A5.st8(ps, 3); + A5.st8(ps+1*8,p0); + A5.st8(ps+2*8,p1); + A5.st8(ps+3*8,p2); + A5.st8(p0, 5); // age= 5 + A5.st8(p1,17); // age=17 + A5.st8(p2,60); // age=60 int trap_arm = A5.step(100); assertEquals(0,trap_arm); - assertEquals( 5+0, A5.ld4s(p0)); - assertEquals(17+1, A5.ld4s(p1)); - assertEquals(60+0, A5.ld4s(p2)); + assertEquals( 5+0, A5.ld8(p0)); + assertEquals(17+1, A5.ld8(p1)); + assertEquals(60+0, A5.ld8(p2)); } @Test -- cgit v1.2.3