From d32f97238c903765dec4e9a9f3cbfa5fd12cded6 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 10 Aug 2026 11:11:18 -0700 Subject: Chapter 25: Modules, Separate Compilation, and SSA Construction 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 Co-authored-by: Claude Opus 5 --- .../com/seaofnodes/simple/node/MemMergeNode.java | 191 +++++++++++++-------- 1 file changed, 123 insertions(+), 68 deletions(-) (limited to 'src/main/java/com/seaofnodes/simple/node/MemMergeNode.java') diff --git a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java index 7a329117..dfe8794d 100644 --- a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java @@ -4,99 +4,154 @@ import com.seaofnodes.print.ExprPrinter; import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.BAOS; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; + import java.util.*; -/** A default slice and explicit alias overrides. A null default means partial - * memory: absent aliases are not covered, rather than having unknown contents. +/** + * Memory Merge - a merge of many aliases into a "fat memory". All aliases + * are here, but most will be lazy - take the default fat memory. */ public class MemMergeNode extends Node { - public MemMergeNode(MemMergeNode mem) { super(mem); } - public MemMergeNode(Node bulk) { super(null,bulk); _type = TypeMem.BOT; } - public MemMergeNode(Node bulk, int alias, Node precise) { - this(bulk); - alias(alias,precise); - } - public Node alias(int alias) { - Node n = alias < nIns() ? in(alias) : null; - assert n!=null || !(in(1) instanceof BulkMemPhiNode bulk) || !bulk.isSplit(alias); - n = n==null ? in(1) : n; - assert n!=null : "Alias not covered: "+alias; - return n; - } + public MemMergeNode( Node ...nodes) { super(nodes); _type = TypeMem.BOT; } + public MemMergeNode(MemMergeNode mem) { super(mem); } + @Override public Tag serialTag() { return Tag.MemMerge; } + public void packed( BAOS baos, HashMap strs, HashMap types, IdentityHashMap anodes ) { baos.packed1(nIns()); } + static Node make( BAOS bais ) { Node mem = new MemMergeNode(); mem.setDefX(bais.packed1()-1,null); return mem; } - public void alias(int alias, Node mem) { - assert alias > 1; - while( nIns()<=alias ) addDef(null); - setDef(alias,mem); - } + @Override public String label() { return "ALLMEM"; } + @Override public boolean isMem() { return true; } - // Scalar contents of one alias. New zeroes the allocated fields; - // join it with the incoming contents for all previously allocated objects. - // Phis use their cached types, so this query does not recurse around loops. - static Type contents(Node mem, int alias, Node dep) { - // A loop memory Phi can also be a user of the querying Store. - // Its type changing still needs to revisit this query. - dep.addDepForwards(mem); - if( mem instanceof CastNode cast ) return contents(cast.in(1),alias,dep); - if( mem instanceof MemMergeNode merge ) - return contents(merge.alias(alias),alias,dep); - if( mem instanceof ProjNode proj && proj.in(0) instanceof NewNode nnn ) { - assert proj._idx==1 && nnn.field(alias)!=null; - dep.addDep(nnn); - if( dep.addDep(nnn.in(0))._type.isHigh() ) return Type.TOP; - return contents(nnn.mem(),alias,dep).meet(nnn.field(alias)._t.makeZero()); + @Override + protected ExprPrinter _print1(ExprPrinter p) { + p.p("MEM[ "); + for( int j=2; j _print1(ExprPrinter p) { - p.p("MEM["); - for( int i=1; i=nIns() || in(i)==null) ) - alias(i,mem.in(i)); + // A dead memory cycle can lose its last use when we bypass mem. + // Keep the peephole's result alive until the worklist sees it. + keep(); + // Goal is to swap my default mem with mem's default mem + for( int i=2; i=nIns() || in(i)==null ) + setDefX(i,mem.in(i)); + } + } CodeGen.CODE.add(mem.in(1)); setDef(1,mem.in(1)); - return this; + return unkeep(); } - assert BulkMemPhiNode.checkMerge(this); + return progress ? this : null; } + + + public Node in( Var v ) { return in(v._idx); } + + public Node alias( int alias ) { + assert !(in(1) instanceof BulkMemPhiNode bulk && bulk.isSplit(alias) && + (alias >= nIns() || in(alias)==null)); + return alias < nIns() && in(alias)!=null ? in(alias) : in(1); + } + + public Node alias( int alias, Node st ) { return setDefX(alias,st); } + + // Now one-time do a useless-phi removal + void _useless( ) { + for( int i=1; i