diff options
| author | Cliff Click <cliffc@acm.org> | 2024-12-29 21:29:31 -0800 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-01-15 15:07:30 -0800 |
| commit | 5fe11b24e49c0a7bb84eeb76f724133e3298a1a9 (patch) | |
| tree | 7f6058ed0404d241a6988c69c1aa452ab52ebf13 /chapter18 | |
| parent | 5400096ec10da839cf2006a8a02e11ffeff521dd (diff) | |
| download | Simple-5fe11b24e49c0a7bb84eeb76f724133e3298a1a9.tar.gz Simple-5fe11b24e49c0a7bb84eeb76f724133e3298a1a9.zip | |
More getting errors reliable
...with and without peeps. Float moves out of the TypeNil set.
Eval2 picks up the FLT compares.
Diffstat (limited to 'chapter18')
11 files changed, 94 insertions, 87 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java index 235d2414..6267c09d 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java @@ -648,7 +648,7 @@ public class Parser { } private Node widenInt( Node expr, Type t ) { - return expr._type instanceof TypeInteger && t instanceof TypeFloat + return (expr._type instanceof TypeInteger || expr._type==Type.NIL) && t instanceof TypeFloat ? peep(new ToFloatNode(expr)) : expr; } @@ -706,7 +706,7 @@ public class Parser { // 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) : ZERO); + : (t==Type.BOTTOM ? con(t) : (t instanceof TypeInteger ? ZERO : con(TypeFloat.FZERO))); } // Lift expression, based on type @@ -1203,11 +1203,11 @@ public class Parser { // Happens when parsing known dead code, which often has other typing // issues. Since the code is dead, possibly due to inlining, lets not // spoil the user experience with error messages. - if( ctrl()._type==Type.XCONTROL ) { - if( expr.isUnused() ) expr.kill(); // Losing last use of expr - // Exit out via parsing the trailing expression - return matchOpx( '=', '=' ) ? parseAsgn() : parsePostfix( con( Type.TOP ) ); - } + //if( ctrl()._type==Type.XCONTROL ) { + // if( expr.isUnused() ) expr.kill(); // Losing last use of expr + // // Exit out via parsing the trailing expression + // return matchOpx( '=', '=' ) ? parseAsgn() : parsePostfix( con( Type.TOP ) ); + //} // if( expr._type==Type.NIL ) diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java index 7f959ff3..094f2bf1 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java @@ -18,8 +18,8 @@ public abstract class LogicalNode extends Node { @Override public String err() { if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; - if( !(in(1)._type instanceof TypeInteger) ) return "Cannot '"+op()+"' " + in(1)._type; - if( !(in(2)._type instanceof TypeInteger) ) return "Cannot '"+op()+"' " + in(2)._type; + if( !(in(1)._type instanceof TypeInteger) ) return "Cannot '"+op()+"' " + in(1)._type.glb(); + if( !(in(2)._type instanceof TypeInteger) ) return "Cannot '"+op()+"' " + in(2)._type.glb(); return null; } } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java index 8311405d..44d3a587 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java @@ -30,7 +30,7 @@ public class RoundF32Node extends Node { Type t1 = lhs._type; // RoundF32 of float - if( t1 instanceof TypeFloat tf && tf._f32 ) + if( t1 instanceof TypeFloat tf && tf._sz==32 ) return lhs; return null; 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 4557a29e..0661ac2c 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java @@ -20,8 +20,9 @@ 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 i0.value()==0 ? Type.NIL : TypeFloat.constant(i0.value()); + return TypeFloat.constant(i0.value()); return TypeFloat.F64; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java index 9f9f688a..cb51a847 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java @@ -195,7 +195,7 @@ public class Type { public Type makeZero() { return Type.NIL; } /** Compute greatest lower bound in the lattice */ - public Type glb() { return Type.NIL; } + public Type glb() { return Type.BOTTOM; } // Is forward-reference public boolean isFRef() { return false; } 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 143adbcd..df99b630 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java @@ -1,95 +1,92 @@ package com.seaofnodes.simple.type; import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.Utils; import java.util.ArrayList; /** * Float Type */ -public class TypeFloat extends TypeNil { +public class TypeFloat extends Type { - public final static TypeFloat ONE = constant(1.0); - public final static TypeFloat F32 = make((byte)3, true, 0); - public final static TypeFloat NF64 = make((byte)2,false, 0); - public final static TypeFloat F64 = make((byte)3,false, 0); + public final static TypeFloat ONE = constant(1.0); + public final static TypeFloat FZERO = constant(0.0); + public final static TypeFloat F32 = make(32, 0); + public final static TypeFloat F64 = make(64, 0); - // true for 32bits, false for 64bits - public final boolean _f32; + // - high -64, high -32, con 0, low +32, low +64 + public final byte _sz; /** * The constant value or 0 */ public final double _con; - private TypeFloat(byte nil, boolean f32, double con) { - super(TFLT,nil); - assert !isConstant() || ((float)con == con) == f32; - _f32 = f32; + private TypeFloat(byte sz, double con) { + super(TFLT); + _sz = sz; _con = con; } - private static TypeFloat make(byte nil, boolean f32, double con) { - return new TypeFloat(nil,f32,con).intern(); - } - @Override public TypeFloat makeFrom(byte nil) { - return nil==_nil ? this : make(nil,_f32,_con); + private static TypeFloat make(int sz, double con) { + return new TypeFloat((byte)sz,con).intern(); } - public static TypeFloat constant(double con) { assert con!=0; return make((byte)2,((float)con)==con, con); } + public static TypeFloat constant(double con) { return make(0, con); } public static void gather(ArrayList<Type> ts) { ts.add(F64); ts.add(F32); ts.add(constant(3.141592653589793)); } @Override public String str() { - if( isConstant() ) - return ""+_con+(_f32 ? "f" : ""); - String s = ""; - if( isHigh() ) s = "~"; - if( 1 <= _nil && _nil <= 2 ) // Disallow nil? - s += "n"; - s += "f"; - s += _f32 ? "32" : "lt"; - return s; + return switch( _sz ) { + case -64 -> "~flt"; + case -32 -> "~f32"; + case 0 -> ""+_con+((float)_con==_con ? "f" : ""); + case 32 -> "f32"; + case 64 -> "flt"; + default -> throw Utils.TODO(); + }; } + private boolean isF32() { return ((float)_con)==_con; } - @Override public boolean isConstant() { return _con!=0; } - @Override public int log_size() { return _f32 ? 2 : 3; } + @Override public boolean isConstant() { return _sz==0; } + @Override public int log_size() { return _sz==32 || _sz==-32 ? 2 : 3; } public double value() { return _con; } @Override public TypeFloat xmeet(Type other) { + TypeFloat f = (TypeFloat)other; // Invariant from caller: 'this' != 'other' and same class (TypeFloat). TypeFloat i = (TypeFloat)other; // Contract - if( isConstant() && i.isHigh() ) return i._f32 && ! _f32 ? NF64 : this; - if( i.isConstant() && isHigh() ) return _f32 && !i._f32 ? NF64 : i ; - - - // From online Karnaugh map; if both values are small the result is - // small, otherwise the result is small if the otherside is high. - boolean f32 = (_f32&i._f32) | (i.isHigh()&_f32) | (isHigh()&i._f32); - return make(xmeet0(i), f32, 0); + // Larger size in i1, smaller in i0 + TypeFloat i0 = _sz < i._sz ? this : i; + TypeFloat i1 = _sz < i._sz ? i : this; + + if( i1._sz== 64 ) return F64; + if( i0._sz==-64 ) return i1; + if( i1._sz== 32 ) + return i0._sz==0 && !i0.isF32() ? F64 : F32; + if( i1._sz!= 0 ) return i1; + // i1 is a constant + if( i0._sz==-32 ) + return i1.isF32() ? i1 : F64; + // Since both are constants, and are never equals (contract) unequals + // constants fall to bottom + return i0.isF32() && i1.isF32() ? F32 : F64; } @Override public Type dual() { - if( isConstant() ) return this; // Constants are a self-dual - return make(dual0(),_f32,0); + return isConstant() ? this : make(-_sz,0); // Constants are a self-dual } - // RHS is NIL - @Override Type meet0() { - // From high, falling to the least Float that contains a zero - return isHigh() || _f32 ? F32 : F64; - } - - @Override public Type glb() { return F64; } @Override - int hash() { return (int)(Double.hashCode(_con) ^ (_f32 ? 2048 : 0) ^ super.hash()); } + int hash() { return (int)(Double.hashCode(_con) ^ _sz ^ (1<<17)); } @Override public boolean eq( Type t ) { TypeFloat i = (TypeFloat)t; // Contract - return _con==i._con && _f32==i._f32 && super.eq(i); + return _con==i._con && _sz==i._sz; } } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java index 9438abe2..9ed4c7a8 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java @@ -19,7 +19,12 @@ public class TypeMem extends Type { public final int _alias; public final Type _t; // Memory contents, some scalar type - private TypeMem(int alias, Type t) { super(TMEM); _alias = alias; _t = t; } + private TypeMem(int alias, Type t) { + super(TMEM); + assert alias!=0 || (t==Type.TOP || t==Type.BOTTOM); + _alias = alias; + _t = t; + } public static TypeMem make(int alias, Type t) { return new TypeMem(alias,t).intern(); } public static final TypeMem TOP = make(0, Type.TOP ); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java index 03c67ce9..aee623ba 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java @@ -48,6 +48,7 @@ public abstract class TypeNil extends Type { @Override public boolean isConstant () { return false; } @Override public boolean isHighOrConst() { return isHigh() || isConstant(); } + @Override public Type glb() { return Type.NIL; } public boolean notNull() { return _nil==1 || _nil==2; } public boolean nullable() { return _nil==3; } diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 1f6df190..cdb9e923 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -288,9 +288,8 @@ struct s0 { int f0; }; return new s0; int v0=null.f0; """); - code.parse().opto(); - assertEquals("return s0;", code.print()); - assertEquals("s0{f0=0}", Eval2.eval(code, 0)); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Accessing unknown field 'f0' from 'null'",e.getMessage()); } } @Test diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java index 77cbf115..580d3b0a 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java @@ -101,32 +101,36 @@ public abstract class Eval2 { // From here down shamelessly copied from Evaluator, written by @Xmilia private static Object compute( Node n ) { return switch( n ) { - case AddFNode adf -> d(adf.in(1)) + d(adf.in(2)); - case AddNode add -> x(add.in(1)) + x(add.in(2)); - case AndNode and -> x(and.in(1)) & x(and.in(2)); - case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L; // Bool EQ supports pointers, nil, and integers - case BoolNode.LE le -> x( le.in(1)) <= x(le .in(2)) ? 1L : 0L; - case BoolNode.LT lt -> x( lt.in(1)) < x(lt .in(2)) ? 1L : 0L; + case AddFNode adf -> d(adf.in(1)) + d(adf.in(2)); + case AddNode add -> x(add.in(1)) + x(add.in(2)); + case AndNode and -> x(and.in(1)) & x(and.in(2)); + case BoolNode.EQF eqf -> d(eqf.in(1)) == d(eqf.in(2)) ? 1L : 0L; + case BoolNode.LEF lef -> d(lef.in(1)) <= d(lef.in(2)) ? 1L : 0L; + case BoolNode.LTF ltf -> d(ltf.in(1)) < d(ltf.in(2)) ? 1L : 0L; + case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L; // Bool EQ supports pointers, nil, and integers + case BoolNode.LE le -> x(le .in(1)) <= x(le .in(2)) ? 1L : 0L; + case BoolNode.LT lt -> x(lt .in(1)) < x(lt .in(2)) ? 1L : 0L; case CastNode cast -> val(cast.in(1)); case ConstantNode con -> con(con._con); - case DivFNode dvf -> d(dvf.in(2))==0 ? 0D : d(dvf.in(1)) / d(dvf.in(2)); - case DivNode div -> x(div.in(2))==0 ? 0L : x(div.in(1)) / x(div.in(2)); - case LoadNode ld -> load(ld); - case MinusNode sub -> - x(sub.in(1)); - case MulNode mul -> x(mul.in(1)) * x(mul.in(2)); - case NewNode alloc -> alloc(alloc); - case NotNode not -> x(not.in(1)) == 0 ? 1L : 0L; - case OrNode or -> x(or .in(1)) | x(or .in(2)); - case ProjNode proj -> proj._type instanceof TypeMem ? "$mem" : val(proj.in(0)); + case DivFNode dvf -> d(dvf.in(2))==0 ? 0D : d(dvf.in(1)) / d(dvf.in(2)); + case DivNode div -> x(div.in(2))==0 ? 0L : x(div.in(1)) / x(div.in(2)); + case LoadNode ld -> load(ld); + case MinusFNode mnf -> - d(mnf.in(1)); + case MinusNode sub -> - x(sub.in(1)); + case MulNode mul -> x(mul.in(1)) * x(mul.in(2)); + case NewNode alloc-> alloc(alloc); + case NotNode not -> x(not.in(1)) == 0 ? 1L : 0L; + case OrNode or -> x(or .in(1)) | x(or .in(2)); + case ProjNode proj -> proj._type instanceof TypeMem ? "$mem" : val(proj.in(0)); case ReadOnlyNode read -> val(read.in(1)); - case SarNode sar -> x(sar.in(1)) >> x(sar.in(2)); + case SarNode sar -> x(sar.in(1)) >> x(sar.in(2)); case ScopeMinNode merge-> "$mem"; - case ShlNode shl -> x(shl.in(1)) << x(shl.in(2)); - case ShrNode shr -> x(shr.in(1)) >>>x(shr.in(2)); - case StoreNode st -> store(st); - case SubNode sub -> x(sub.in(1)) - x(sub.in(2)); - case ToFloatNode toflt -> (double)x(toflt.in(1)); - case XorNode xor -> x(xor.in(1)) ^ x(xor.in(2)); + case ShlNode shl -> x(shl.in(1)) << x(shl.in(2)); + case ShrNode shr -> x(shr.in(1)) >>>x(shr.in(2)); + case StoreNode st -> store(st); + case SubNode sub -> x(sub.in(1)) - x(sub.in(2)); + case ToFloatNode toflt-> (double)x(toflt.in(1)); + case XorNode xor -> x(xor.in(1)) ^ x(xor.in(2)); default -> throw Utils.TODO(); }; } diff --git a/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java index effd5db5..d94f5b5a 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java @@ -35,10 +35,10 @@ public class TypeTest { Assert.assertEquals(TypeStruct.BOT, s1.meet(s2)); Assert.assertEquals(TypeMem .BOT, m1.meet(m2)); - Assert.assertEquals(TypeMem.make(0,TypeFloat.F64), m1.meet(m3)); + Assert.assertEquals(TypeMem.make(0,Type.BOTTOM), m1.meet(m3)); Assert.assertEquals(TypeMem .BOT, m3.meet(m4)); - Assert.assertEquals(m1, m1.glb()); + Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.glb()); Assert.assertEquals(TypeMem.make(1,Type.XNIL), m1.dual()); Assert.assertEquals(m4.dual(), m4.glb().dual()); |
