summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/StartNode.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-08-10 11:11:18 -0700
committerCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
commitd32f97238c903765dec4e9a9f3cbfa5fd12cded6 (patch)
treea5ac731801ef7066bab6359c4e85c2bdd20082a6 /src/main/java/com/seaofnodes/simple/node/StartNode.java
parentb5ebb2032aa04cf4506d533127d373d4cf5a25c6 (diff)
downloadSimple-linear.tar.gz
Simple-linear.zip
Chapter 25: Modules, Separate Compilation, and SSA Constructionlinear
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: Symious <14933944+symious@users.noreply.github.com> Co-authored-by: Jun Kawasaki <jun784@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/main/java/com/seaofnodes/simple/node/StartNode.java')
-rw-r--r--src/main/java/com/seaofnodes/simple/node/StartNode.java58
1 files changed, 48 insertions, 10 deletions
diff --git a/src/main/java/com/seaofnodes/simple/node/StartNode.java b/src/main/java/com/seaofnodes/simple/node/StartNode.java
index e13d35c0..84c8a3a7 100644
--- a/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -5,39 +5,76 @@ import com.seaofnodes.print.ExprPrinter;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
+import java.util.Arrays;
import java.util.HashSet;
-import static com.seaofnodes.simple.util.Utils.TODO;
-/** Start supplies control, whole memory, and the argument, in that order. */
+/**
+ * The Start node represents the external world calling, be it calling the
+ * entry <clinit> or just some linked caller calling.
+ * <p>
+ * Start initially has 1 input (arg) from outside and the initial control.
+ * In ch10 we also add mem aliases as structs get defined; each field in struct
+ * adds a distinct alias to Start's tuple.
+ * <p>
+ * By ch25, Start is the external world (or linker) calling with everything
+ * that has escaped. Start is NOT the entry <clinit> itself, which can assume
+ * no memory nor fidxs exist nor escaped. Start gets escaped things from Stop;
+ * together these close the Grand Cycle between the code we know and the code
+ * we don't.
+ */
public class StartNode extends LoopNode implements MultiNode {
final Type _arg;
- public StartNode(Type arg) { super(null,null); _arg = arg; _type = compute(); }
+ public StartNode(StartNode start, StopNode stop, Type arg) { super(null,start,stop); _arg = arg; }
public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; }
-
- @Override public String label() { return "Start"; }
+ @Override public Tag serialTag() { return Tag.Start; }
+ public Type arg() { return _arg; }
@Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
return p.p(label());
}
- @Override public CFGNode cfg0() { return null; }
+ @Override public CFGNode cfg0() { return null; }
// Get the one control following; error to call with more than one e.g. an
- // IfNode or other multi-way branch. For Start, its "main"
+ // IfNode or other multi-way branch. For Start, it's the class init for
+ // this compilation unit.
@Override public CFGNode uctrl() {
- // Find "main", it's the start.
+ // Find module.<clinit>, it's the start.
CFGNode C = null;
for( Node use : _outputs )
- if( use instanceof FunNode fun && fun.sig().isa(CodeGen.CODE._main) )
+ if( use instanceof FunNode fun && fun.isModInit() )
{ assert C==null; C = fun; }
+ if( C==null )
+ for( FunNode fun : CodeGen.CODE._linker )
+ if( fun!=null && !fun.isDead() && fun.isModInit() )
+ { assert C==null; C = fun; }
return C;
}
+ boolean escapedFIDX(int fidx) {
+ // Public class fields are callable by the unknown external world
+ // regardless of the current SCCP approximation of Start memory.
+ if( CodeGen.CODE.publicFIDX(fidx) ) return true;
+ if( !(_type instanceof TypeTuple tt) )
+ return !_type.isHigh(); // TOP never escapes, BOTTOM always escapes
+ TypeMem tmem = (TypeMem)tt._types[1];
+ if( tmem == TypeMem.BOT ) return false;
+ if( tmem == TypeMem.TOP ) return false;
+ if( XInt.isHigh(tmem._escFs) )
+ return false;
+ return XInt.bit(tmem._escFs,fidx);
+ }
@Override public TypeTuple compute() {
- return TypeTuple.make(Type.CONTROL,TypeMem.BOT,_arg);
+ StopNode stop = (StopNode)in(1);
+ TypeMem tmem = stop._type instanceof TypeTuple tt
+ ? tt.mem()
+ : stop._type.isHigh() ? TypeMem.START : TypeMem.BOT;
+ assert tmem._alias==1 && !tmem._one;
+ return TypeTuple.make(Type.CONTROL,tmem,_arg);
}
@Override public Node idealize() { return null; }
@@ -46,4 +83,5 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public int idepth() { return 0; }
@Override public CFGNode idom(Node dep) { return null; }
+ @Override public boolean eq( Node n ) { return true; }
}