summaryrefslogtreecommitdiff
path: root/chapter18
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-12-29 21:29:31 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commit5fe11b24e49c0a7bb84eeb76f724133e3298a1a9 (patch)
tree7f6058ed0404d241a6988c69c1aa452ab52ebf13 /chapter18
parent5400096ec10da839cf2006a8a02e11ffeff521dd (diff)
downloadSimple-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')
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/Parser.java14
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java3
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/Type.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFloat.java91
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeMem.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java1
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter10Test.java5
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Eval2.java48
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/TypeTest.java4
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());