summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/Parser.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-02-07 08:58:36 -0800
committerCliff Click <cliffc@acm.org>2025-02-07 08:58:36 -0800
commit2aa8c5d1d0659bd1c828134f1a1f14d025a2d0f1 (patch)
tree0532f3ba5d74de006fcaa906dad9b787ebb06e2e /src/main/java/com/seaofnodes/simple/Parser.java
parent68dc63b9390bbe4ec50cc1b814d4e559e459c057 (diff)
downloadSimple-linear-chapter19.tar.gz
Simple-linear-chapter19.zip
Ch# Chapter 19: Instruction Selection and Portable Compilationlinear-chapter19
Co-authored-by: hadha <helsgithub15@gmail.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Diffstat (limited to 'src/main/java/com/seaofnodes/simple/Parser.java')
-rw-r--r--src/main/java/com/seaofnodes/simple/Parser.java107
1 files changed, 53 insertions, 54 deletions
diff --git a/src/main/java/com/seaofnodes/simple/Parser.java b/src/main/java/com/seaofnodes/simple/Parser.java
index c16e3267..61a53d68 100644
--- a/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/src/main/java/com/seaofnodes/simple/Parser.java
@@ -2,6 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import java.text.ParseException;
import java.util.*;
/**
@@ -13,23 +14,12 @@ import java.util.*;
*/
public class Parser {
- /**
- * A Global Static, unique to each compilation. This is a public, so we
- * can make constants everywhere without having to thread the StartNode
- * through the entire parser and optimizer.
- * <p>
- * To make the compiler multithreaded, this field will have to move into a TLS.
- */
- public static StartNode START;
-
public static ConstantNode ZERO; // Very common node, cached here
public static ConstantNode NIL; // Very common node, cached here
public static XCtrlNode XCTRL; // Very common node, cached here
- // Next available memory alias number
- static int ALIAS;
-
- public StopNode STOP;
+ // Compile driver
+ public final CodeGen _code;
// The Lexer. Thin wrapper over a byte[] buffer with a cursor.
private final Lexer _lexer;
@@ -51,7 +41,7 @@ public class Parser {
/**
* List of keywords disallowed as identifiers
*/
- private static final HashSet<String> KEYWORDS = new HashSet<>(){{
+ public static final HashSet<String> KEYWORDS = new HashSet<>(){{
add("bool");
add("break");
add("byte");
@@ -98,21 +88,14 @@ public class Parser {
public final HashMap<String, StructNode> INITS;
- public Parser(String source) { this(source, TypeInteger.BOT); }
-
- public Parser(String source, TypeInteger arg) {
- Node.reset();
- IterPeeps.reset();
- Type.reset();
- _lexer = new Lexer(source);
+ public Parser(CodeGen code, TypeInteger arg) {
+ _code = code;
+ _lexer = new Lexer(code._src);
_scope = new ScopeNode();
_continueScope = _breakScope = null;
- START = new StartNode(arg);
- STOP = new StopNode(source);
ZERO = con(TypeInteger.ZERO).keep();
NIL = con(Type.NIL).keep();
XCTRL= new XCtrlNode().peephole().keep();
- ALIAS = 2; // alias 0 for the control, 1 for memory
TYPES = defaultTypes();
INITS = new HashMap<>();
}
@@ -142,13 +125,13 @@ public class Parser {
}
// Debugging utility to find a Node by index
- public static Node find(int nid) { return START.find(nid); }
+ public Node f(int nid) { return _code.f(nid); }
private Node ctrl() { return _scope.ctrl(); }
private <N extends Node> N ctrl(N n) { return _scope.ctrl(n); }
- public StopNode parse() { return parse(false); }
- public StopNode parse(boolean show) {
+ public void parse() { parse(false); }
+ public void parse(boolean show) {
_xScopes.push(_scope);
_scope.define(ScopeNode.CTRL, Type.CONTROL , false, null, _lexer);
_scope.define(ScopeNode.MEM0, TypeMem.BOT , false, null, _lexer);
@@ -158,7 +141,8 @@ public class Parser {
_scope.mem(new MemMergeNode(false));
// Parse whole program, as-if function header "{ int arg -> body }"
- parseFunctionBody(TypeFunPtr.MAIN,loc(),"arg");
+ parseFunctionBody(_code._main,loc(),"arg");
+ _code.link(_code._main)._name = "main";
if( !_lexer.isEOF() ) throw _errorSyntax("unexpected");
@@ -168,9 +152,8 @@ public class Parser {
for( StructNode init : INITS.values() )
init.unkeep().kill();
INITS.clear();
- STOP.peephole();
+ _code._stop.peephole();
if( show ) showGraph();
- return STOP;
}
/**
@@ -184,24 +167,24 @@ public class Parser {
ScopeNode breakScope = _breakScope; _breakScope = null;
ScopeNode continueScope = _continueScope; _continueScope = null;
- FunNode fun = _fun = (FunNode)peep(new FunNode(loc(),START,sig));
+ FunNode fun = _fun = (FunNode)peep(new FunNode(loc(),sig,null,_code._start));
// Once the function header is available, install in linker table -
// allowing recursive functions. Linker matches on declared args and
// exact fidx, and ignores the return (because the fidx will only match
// the exact single function).
- CodeGen.CODE.link(fun);
+ _code.link(fun);
Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole();
// Build a multi-exit return point for all function returns
- RegionNode r = new RegionNode((Node)null,null).init();
+ RegionNode r = new RegionNode((Lexer)null,null,null).init();
assert r.inProgress();
PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init();
PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init();
ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun).init();
fun.setRet(ret);
assert ret.inProgress();
- STOP.addDef(ret);
+ _code._stop.addDef(ret);
// Pre-call the function from Start, with worse-case arguments. This
// represents all the future, yet-to-be-parsed functions calls and
@@ -400,7 +383,7 @@ public class Parser {
// Our current scope is the body Scope
ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection
_scope.addGuards(ifT,pred.unkeep(),false); // Up-cast predicate
- Node expr = parseStatement().keep(); // Parse loop body
+ parseStatement(); // Parse loop body
_scope.removeGuards(ifT);
// Merge the loop bottom into other continue statements
@@ -440,7 +423,7 @@ public class Parser {
_xScopes.pop();
_xScopes.push(exit);
_scope = exit;
- return peep(expr.unkeep());
+ return ZERO;
}
private ScopeNode jumpTo(ScopeNode toScope) {
@@ -598,7 +581,7 @@ public class Parser {
* @return {@code null}
*/
Node showGraph() {
- System.out.println(new GraphVisualizer().generateDotOutput(STOP,_scope,_xScopes));
+ System.out.println(new GraphVisualizer().generateDotOutput(_code._stop,_scope,_xScopes));
return null;
}
@@ -687,7 +670,6 @@ public class Parser {
boolean hasBang = match("!");
Lexer loc = loc();
String name = requireId();
-
// Optional initializing expression follows
boolean xfinal = false;
Node expr;
@@ -711,7 +693,7 @@ public class Parser {
if( !xfinal ) t = t.glb(); // Widen if not final
}
if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() )
- tfp.setName(name);
+ _code.link(tfp)._name = name;
} else {
// Need an expression to infer the type.
@@ -779,7 +761,7 @@ public class Parser {
s.addDef(_scope.in(i));
Var v = _scope._vars.at(i);
if( !v.isFRef() ) // Promote to outer scope, not defined here
- fs.push(Field.make(v._name,v.type(),ALIAS++,v._final));
+ fs.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final));
}
TypeStruct ts = s._ts = TypeStruct.make(typeName, fs.asAry());
TYPES.put(typeName, TypeMemPtr.make(ts));
@@ -835,7 +817,7 @@ public class Parser {
int old2 = pos();
match("!");
String id = _lexer.matchId();
- if( !(peek(',') || peek(';')) )
+ if( !(peek(',') || peek(';') || match("->")) )
return posT(old1);
pos(old2); // Reset lexer to reparse
if( id==null )
@@ -853,7 +835,7 @@ public class Parser {
Type ta = TYPES.get(tname);
if( ta != null ) return (TypeMemPtr)ta;
// Need make an array type.
- TypeStruct ts = TypeStruct.makeAry(TypeInteger.BOT,ALIAS++,t,ALIAS++);
+ TypeStruct ts = TypeStruct.makeAry(TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS());
assert ts.str().equals(tname);
TypeMemPtr tary = TypeMemPtr.make(ts);
TYPES.put(tname,tary);
@@ -1204,20 +1186,29 @@ public class Parser {
if( fs==null )
throw error("Unknown struct type '" + obj._name + "'");
int len = fs.length;
- Node[] ns = new Node[2+len+len];
+ Node[] ns = new Node[2+len];
ns[0] = ctrl(); // Control in slot 0
// Total allocated length in bytes
ns[1] = size;
// Memory aliases for every field
for( int i = 0; i < len; i++ )
- ns[2 +i] = memAlias(fs[i]._alias);
- // Initial values for every field
- for( int i = 0; i < len; i++ )
- ns[2+len+i] = init.get(i+idx);
- Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole();
+ ns[2+i] = memAlias(fs[i]._alias);
+ Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole().keep();
for( int i = 0; i < len; i++ )
memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole());
- return new ProjNode(nnn,1,obj._name).peephole();
+ Node ptr = new ProjNode(nnn.unkeep(),1,obj._name).peephole().keep();
+
+ // Initial nonzero values for every field
+ for( int i = 0; i < len; i++ ) {
+ Node val = init.get( i + idx );
+ if( val._type != val._type.makeZero() ) {
+ Node mem = memAlias(fs[i]._alias);
+ Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._type,mem,ptr,con(obj.offset(i)),val,true).peephole();
+ memAlias(fs[i]._alias,st);
+ }
+ }
+
+ return ptr.unkeep();
}
private static final Ary<Node> ALTMP = new Ary<>(Node.class);
@@ -1261,8 +1252,9 @@ public class Parser {
throw error("Accessing unknown field '" + name + "' from 'null'");
// Sanity check expr for being a reference
- if( !(expr._type instanceof TypeMemPtr ptr) )
- throw error("Expected reference but got " + expr._type.str());
+ if( !(expr._type instanceof TypeMemPtr ptr) ) {
+ throw error( "Expected "+(name=="#" || name=="[]" ? "array" : "reference")+" but found " + expr._type.str() );
+ }
// Sanity check field name for existing
TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name);
@@ -1302,7 +1294,7 @@ public class Parser {
// Arrays include control, as a proxy for a safety range check
// Structs don't need this; they only need a NPE check which is
// done via the type system.
- if( base.isAry() ) load.setDef(0,ctrl());
+ if( base.isAry() && !name.equals("#") ) load.setDef(0,ctrl());
load = peep(load);
// Check for assign-update, "ptr.fld += expr" or "ary[idx]++"
@@ -1366,7 +1358,7 @@ public class Parser {
}
require("->");
// Make a concrete function type, with a fidx
- TypeFunPtr tfp = TypeFunPtr.makeFun(TypeTuple.make(ts.asAry()),Type.BOTTOM);
+ TypeFunPtr tfp = _code.makeFun(TypeTuple.make(ts.asAry()),Type.BOTTOM);
ReturnNode ret = parseFunctionBody(tfp,loc,ids.asAry());
return con(ret._fun.sig());
}
@@ -1400,6 +1392,14 @@ public class Parser {
// Unkeep them all
for( Node arg : args )
arg.unkeep();
+ // Dead into the call? Skip all the node gen
+ if( ctrl()._type == Type.XCONTROL ) {
+ for( Node arg : args )
+ if( arg.isUnused() )
+ arg.kill();
+ return con(Type.TOP);
+ }
+
// Into the call
CallNode call = (CallNode)new CallNode(loc(), args.asAry()).peephole();
@@ -1656,7 +1656,6 @@ public class Parser {
private String parseNumberString() {
int old = _position;
int len = Math.abs(isLongOrDouble());
- _position += len;
return new String(_input,old,len);
}