diff options
Diffstat (limited to 'chapter18')
9 files changed, 96 insertions, 22 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java index 2d98287d..d888f17e 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java @@ -651,7 +651,7 @@ public class Parser { // Auto-narrow wide ints to narrow ints expr = zsMask(expr,t); // Type is sane - if( !expr._type.isa(t) ) + if( expr._type!=Type.BOTTOM && !expr._type.isa(t) ) throw error("Type " + expr._type.str() + " is not of declared type " + t.str()); return expr; } @@ -711,14 +711,16 @@ public class Parser { if( inferType && !_scope.inCon() ) throw errorSyntax("=expression"); // Initial value for uninitialized struct fields. - expr = t instanceof TypeMemPtr tn + expr = switch( t ) { // Nullable pointers get a NIL; not-null get a TOP which // signals that they *must* be initialized in the constructor. - ? (tn.nullable() ? NIL : con(Type.TOP)) - // Bottom signals type inference: they must be initialized in - // the constructor and that's when we'll discover the type. - // Otherwise, its an Integer and use 0. - : (t==Type.BOTTOM ? con(t) : (t instanceof TypeInteger ? ZERO : con(TypeFloat.FZERO))); + case TypeNil tn -> tn.nullable() ? NIL : con(Type.TOP); + case TypeInteger ti -> ZERO; + case TypeFloat tf -> con(TypeFloat.FZERO); + // Bottom signals type inference: they must be initialized in + // the constructor and that's when we'll discover the type. + case Type tt -> { assert tt==Type.BOTTOM; yield con(tt); } + }; } // Lift expression, based on type @@ -727,6 +729,10 @@ public class Parser { if( xfinal && t instanceof TypeMemPtr tmp ) t = tmp.makeRO(); + // Lift type to the declaration. This will report as an error later if + // we cannot lift the type. + if( !lift._type.isa(t) ) + lift = peep(new CastNode(t,null,lift)); // Define a new name if( !_scope.define(name,t,xfinal,lift, loc) ) throw error("Redefining name '" + name + "'", loc); @@ -1356,7 +1362,7 @@ public class Parser { private Node functionCall(Node expr) { if( expr._type == Type.NIL ) throw error("Calling a null function pointer"); - if( !expr._type.isa(TypeFunPtr.BOT) ) + if( !(expr instanceof FRefNode) && !expr._type.isa(TypeFunPtr.BOT) ) throw error("Expected a function but got "+expr._type.glb().str()); expr.keep(); // Keep while parsing args diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java index 98d0ac71..d8a968c1 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import java.util.BitSet; @@ -45,4 +47,12 @@ public class CastNode extends Node { @Override int hash() { return _t.hashCode(); } + + @Override + public Parser.ParseException err() { + // Has a condition to test, so OK + if( in(0) != null ) return null; + // No condition to test, so this must optimize away + throw Utils.TODO(); + } } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java index beb14870..f0c4045d 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java @@ -11,7 +11,7 @@ import java.util.BitSet; * peepholes to the Def. */ public class FRefNode extends ConstantNode { - public static final Type FREF_TYPE = Type.TOP; + public static final Type FREF_TYPE = Type.BOTTOM; public final Var _n; public FRefNode( Var n ) { super(FREF_TYPE); _n = n; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java index 576f8d92..ccabadb4 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -43,6 +43,7 @@ public class StoreNode extends MemOpNode { public Type compute() { Type val = val()._type; TypeMem mem = (TypeMem)mem()._type; // Invariant + if( mem == TypeMem.TOP ) return TypeMem.TOP; Type t = Type.BOTTOM; // No idea on field contents // Same alias, lift val to the declared type and then meet into other fields if( mem._alias == _alias ) { diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java index 0661ac2c..1f4d67e0 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java @@ -21,8 +21,11 @@ public class ToFloatNode extends Node { @Override public Type compute() { if( in(1)._type == Type.NIL ) return TypeFloat.FZERO; - if (in(1)._type instanceof TypeInteger i0 && i0.isConstant() ) - return TypeFloat.constant(i0.value()); + if (in(1)._type instanceof TypeInteger i0 ) { + if( i0.isHigh() ) return TypeFloat.F64.dual(); + if( i0.isConstant() ) + return TypeFloat.constant(i0.value()); + } return TypeFloat.F64; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java index 258cda03..aa205149 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java @@ -47,6 +47,7 @@ public class TypeFloat extends Type { } private boolean isF32() { return ((float)_con)==_con; } + @Override public boolean isHigh () { return _sz< 0; } @Override public boolean isConstant() { return _sz==0; } @Override public int log_size() { return _sz==32 || _sz==-32 ? 2 : 3; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java index 78a94dff..5799fea9 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java @@ -63,7 +63,7 @@ public class TypeFunPtr extends TypeNil { @Override Type xmeet(Type t) { TypeFunPtr that = (TypeFunPtr) t; - return TypeFunPtr.make(xmeet0(that),(TypeTuple)_sig.meet(that._sig), _ret.meet(that._ret),_fidxs | that._fidxs); + return TypeFunPtr.make(xmeet0(that),(TypeTuple)_sig.meet(that._sig), _ret.meet(that._ret), _fidxs | that._fidxs); } @Override @@ -94,8 +94,9 @@ public class TypeFunPtr extends TypeNil { public TypeFunPtr setName(String name) { if( name==null ) return this; - assert _name==null || _name.equals(name); assert _fidxs > 0 && Long.bitCount(_fidxs) == 1; + // Name can be set to different things, just for debug + //assert _name==null || _name.equals(name); _name = name; return this; } @@ -109,9 +110,11 @@ public class TypeFunPtr extends TypeNil { sb.p(x()).p("{ "); if( n && _name!=null ) sb.p(_name); else { - for( Type t : _sig._types ) - _print(sb,g,t).p(" "); + if( _sig._types!=null ) + for( Type t : _sig._types ) + _print(sb,g,t).p(" "); _print(sb.p(g ? "→ " : "-> "),g,_ret).p(" #"); + if( isHigh() ) sb.p("~"); long fidxs = isHigh() ? ~_fidxs : _fidxs; String fidx = fidxs==0 ? "" : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java index 8f8d15a1..9e74ce6d 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -11,14 +11,29 @@ public class Chapter18Test { public void testJig() { CodeGen code = new CodeGen( """ -if( arg ? f : g ) return 1; -val f = {->1}; -val g = {->2}; -return 2; +return 0; +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testJig2() { + CodeGen code = new CodeGen( +""" +struct S { S? next; }; +val f = { int dep, S s -> + if (dep-- == 0) return s; + S? v = f(dep, s); + return v ? v.next : null; +}; +return f(1, new S); """); code.parse().opto().typeCheck().GCM(); - assertEquals("return 0.0f;", code._stop.toString()); - assertEquals("0.0", Eval2.eval(code, 0)); + assertEquals("Stop[ return f( 1,S); return Phi(Region,Parm_s(f,*S {*S? !next; },S,s),Phi(Region,.next,null)); ]", code._stop.toString()); + assertEquals("null", Eval2.eval(code, 0)); + assertEquals("null", Eval2.eval(code, 1)); } @Test @@ -149,6 +164,22 @@ return newS(1).i; assertEquals("1", Eval2.eval(code, 0)); } + // Double forward reference + @Test + public void testFcn7() { + CodeGen code = new CodeGen( +""" +if( arg ? f : g ) return 1; +val f = {->1;}; +val g = {->2;}; +return 2; +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("Stop[ return 1; return 1; return 2; ]", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + } + + // Function break @Test public void testErr1() { @@ -211,4 +242,23 @@ return is_even(arg); assertEquals("0", Eval2.eval(code, 3)); } + // Forward ref to 'x' means that + @Ignore @Test + public void testForwardRef1() { + CodeGen code = new CodeGen( +""" +struct S { + { int } f = { -> return x(); }; +}; +val x = { -> return 1; }; +S? s = null; +for(;;) { + if (s) return s.f; +} +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 0)); + } + } diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java index e68c8fd3..006034e9 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java @@ -224,7 +224,7 @@ public abstract class Eval2 { F.dec(); // Lower ref count // Install replacement Frame; set return result over the CallEnd F = cont._frame; - F.put(cont._cc,rez); // Set return value into CallEnd + F.put0(cont._cc,rez); // Set return value into CallEnd return cont._cc; // Return CallEnd as the new control } |
