summaryrefslogtreecommitdiff
path: root/chapter25/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-08-10 14:09:04 -0700
committerCliff Click <cliffc@acm.org>2026-08-10 14:09:04 -0700
commit8f5b226cf472bc249b935320b8f3b7ac71d09579 (patch)
tree0499933cc8762528c4d16c0dd13b8812f9470607 /chapter25/src
parent51f1f8f4b871e3b52eb0c5d18b03f362a2b37791 (diff)
downloadSimple-8f5b226cf472bc249b935320b8f3b7ac71d09579.tar.gz
Simple-8f5b226cf472bc249b935320b8f3b7ac71d09579.zip
A few missed ser/de-ser tags
A little less aggressive FunPtr trimming before Opto
Diffstat (limited to 'chapter25/src')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java17
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java11
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/type/TypeInteger.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/type/TypeScalar.java12
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys.smp3
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp6
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryi64.smp29
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp50
8 files changed, 110 insertions, 23 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java
index a9d03543..5018f5d6 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java
@@ -154,14 +154,14 @@ public class FunNode extends RegionNode {
}
// Attempt to get rid of the unknown caller.
- // - Must be past Parser, which invents new calls "from whole cloth".
+ // - Must be past pessimistic Iter, which discovers and links calls
+ // through class-field loads and other initially imprecise values.
// - FIDX is not in the escape set
// - Not called anywhere else; post Opto called-not-escaped functions need to still be hooked to start
if( in(1) instanceof StartCUNode start ) {
boolean preOpto = CodeGen.CODE._phase == null ||
CodeGen.CODE._phase.ordinal() < CodeGen.Phase.Opto.ordinal();
- if( !start.escapedFIDX(_sig.fidx()) && nIns()<=2 && _ret!=null &&
- !(preOpto && hasFunPtr()) ) {
+ if( !preOpto && !start.escapedFIDX(_sig.fidx()) && nIns()<=2 && _ret!=null ) {
_compunit._stop.delDef(_compunit._stop._inputs.find(ret()));
return removeDeadPath(1);
} else {
@@ -186,17 +186,6 @@ public class FunNode extends RegionNode {
return null;
}
- // Before SCCP has discovered all Call edges, a live function pointer is
- // enough reason to retain the unknown-caller Start edge.
- private boolean hasFunPtr() {
- for( Node use : ret().outs() )
- if( use instanceof FunPtrNode && !use.isDead() ) {
- addDep(use);
- return true;
- }
- return false;
- }
-
// Bypass Region idom, always assume depth == 1, one more than Start,
// unless folding
@Override public int idepth() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
index cbed5996..8d8d3950 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
@@ -12,13 +12,20 @@ public class TFPX86 extends FunPtrNode implements MachNode, RIPRelSize {
private byte _opLen;
final String _ext; // External name
// Pointer to a Simple function
- TFPX86( FunPtrNode fptr ) { super(fptr); _ext = null; }
+ TFPX86( FunPtrNode fptr ) { this((TypeFunPtr)fptr._type,null); }
+ // Spill clone: copy inputs without registering their reverse edges;
+ // insertBefore will place and register the clone in its use block.
+ private TFPX86( TFPX86 fptr ) { super(fptr); _ext = fptr._ext; }
// Pointer to an Extern "C" function
TFPX86( TypeFunPtr fptr, String ext ) { super(fptr,CodeGen.CODE._start,null); _type = fptr; _ext = ext; }
@Override public String op() { return "ldx"; }
@Override public String label() { return op(); }
+ // The ideal FunPtrNode is pinned because its Return input is a lifetime
+ // hook. After selection this is an ordinary cloneable load-address
+ // instruction and must be scheduled down near its actual use.
+ @Override public boolean isPinned() { return false; }
@Override public boolean isClone() { return true; }
- @Override public TFPX86 copy() { return new TFPX86((TypeFunPtr)_con,_ext); }
+ @Override public TFPX86 copy() { return new TFPX86(this); }
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
@Override public void encoding( Encoding enc ) {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter25/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
index 4245626a..25c3fa6f 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
@@ -193,7 +193,8 @@ public class TypeInteger extends TypeScalar {
baos.write(TAGOFFS[_type] + 6);
baos.packed8(_min);
baos.packed8(_max);
- baos.packed1(_widen);
+ assert -3 <= _widen && _widen <= 3;
+ baos.packed1(_widen + 3);
}
}
@@ -205,7 +206,7 @@ public class TypeInteger extends TypeScalar {
case 3 -> BOOL;
case 4 -> ZERO;
case 5 -> constant(bais.packed8());
- case 6 -> make(bais.packed8(),bais.packed8(),(byte)bais.packed1());
+ case 6 -> make(bais.packed8(),bais.packed8(),(byte)(bais.packed1()-3));
default -> throw Utils.TODO();
};
}
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/type/TypeScalar.java b/chapter25/src/main/java/com/seaofnodes/simple/type/TypeScalar.java
index 4fec3c33..7b5d6317 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/type/TypeScalar.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/type/TypeScalar.java
@@ -41,14 +41,16 @@ public class TypeScalar extends Type {
@Override boolean _isGLB(boolean mem) { return this == BOT; }
@Override Type _glb(boolean mem) { return BOT; }
- @Override int TAGOFF() { return 1; }
+ // Reserve tags for both lattice endpoints. Unlike most concrete scalar
+ // families, generic scalar TOP can survive into a serialized graph.
+ @Override int TAGOFF() { return 2; }
@Override public void packed(BAOS baos, HashMap<String,Integer> strs) {
- assert this == BOT;
- baos.write(TAGOFFS[_type]);
+ assert this == BOT || this == TOP;
+ baos.write(TAGOFFS[_type] + (this == BOT ? 0 : 1));
}
static TypeScalar packed(int tag) {
- assert tag == 0;
- return BOT;
+ assert tag == 0 || tag == 1;
+ return tag == 0 ? BOT : TOP;
}
@Override public String str() { return isHigh() ? "~scalar" : "scalar"; }
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys.smp
new file mode 100644
index 00000000..1725c57d
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys.smp
@@ -0,0 +1,3 @@
+// Reduced multi-compilation-unit reproducer for order-sensitive inlining.
+var aryu8 = aryu8;
+var aryi64 = aryi64;
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp
new file mode 100644
index 00000000..e3dd6140
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/Ary.smp
@@ -0,0 +1,6 @@
+// Array utilities, discovered indirectly from aryu8.
+val copy = { u8[] dst, int doff, u8[~] src, int soff, int len ->
+ for( int i=0; i<len; i++ )
+ dst[i+doff] = src[i+soff];
+ return dst;
+};
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryi64.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryi64.smp
new file mode 100644
index 00000000..53c93666
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryi64.smp
@@ -0,0 +1,29 @@
+struct aryi64 {
+ u32 !len = 0;
+ i64[] !buf;
+
+ new aryi64 = { i64[] b -> buf = b; };
+
+ val _grow = { int len2 ->
+ if( len+len2 < buf# ) return self;
+ int newlen = buf# * 2;
+ while( len+len2 >= newlen ) newlen *= 2;
+ i64[] !buf2 = new i64[newlen];
+ for( int i=0; i<buf#; i++ )
+ buf2[i] = buf[i];
+ buf = buf2;
+ self;
+ };
+
+ val add = { i64 c ->
+ _grow(1).buf[len++] = c;
+ self;
+ };
+
+ val str = { ->
+ var str = new aryu8(new u8[1]).add('[');
+ for( int i=0; i<len; i++ )
+ str.num(buf[i]).add(',').add(' ');
+ str.undo(2).add(']');
+ };
+};
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp
new file mode 100644
index 00000000..112a0321
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/test_smp/seed_repro/sys/aryu8.smp
@@ -0,0 +1,50 @@
+struct aryu8 {
+ u32 !len = 0;
+ u8[] !buf;
+
+ new aryu8 = { u8[] b -> buf = b; };
+
+ val _grow = { int len2 ->
+ if( len+len2 < buf# ) return self;
+ int newlen = buf# * 2;
+ while( len+len2 >= newlen ) newlen *= 2;
+ u8[] !buf2 = new u8[newlen];
+ Ary.copy(buf2,0,buf,0,buf#);
+ buf = buf2;
+ self;
+ };
+
+ val clear = { -> len = 0; self; };
+
+ val add = { u8 c ->
+ _grow(1).buf[len++] = c;
+ self;
+ };
+
+ val addAry = { u8[~] ary ->
+ _grow(ary#);
+ Ary.copy(buf,len,ary,0,ary#);
+ len += ary#;
+ self;
+ };
+
+ val undo = { int x ->
+ len = len >= x ? len-x : 0;
+ self;
+ };
+
+ val num = { i64 x ->
+ if( !x ) { add('0'); return self; }
+ if( x < 0 ) { add('-'); x = -x; }
+ i64 ten = 1, log = 0;
+ while( ten <= x ) { ten *= 10; log++; }
+ for( int i=0; i<log; i++ ) {
+ ten /= 10;
+ i64 q = x/ten;
+ u8 digit = q+'0';
+ add(digit);
+ x -= q*ten;
+ }
+ self;
+ };
+};