From dead068fc0e3d637419fa5508c32856bc8340dc9 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sun, 18 Aug 2024 09:40:56 -0700 Subject: handle all unsigned int variants and-masking and typenames for all! --- .../main/java/com/seaofnodes/simple/Parser.java | 46 +++++++++++++++-- .../java/com/seaofnodes/simple/node/AndNode.java | 57 ++++++++++++++++++++++ .../main/java/com/seaofnodes/simple/node/Node.java | 6 +-- .../java/com/seaofnodes/simple/type/TypeFloat.java | 2 +- .../com/seaofnodes/simple/type/TypeInteger.java | 13 ++--- 5 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java (limited to 'chapter14/src/main') diff --git a/chapter14/src/main/java/com/seaofnodes/simple/Parser.java b/chapter14/src/main/java/com/seaofnodes/simple/Parser.java index 032b4867..de5565ab 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/Parser.java @@ -52,7 +52,9 @@ public class Parser { * List of keywords disallowed as identifiers */ private static final HashSet KEYWORDS = new HashSet<>(){{ + add("bool"); add("break"); + add("byte"); add("continue"); add("else"); add("false"); @@ -64,8 +66,11 @@ public class Parser { add("return"); add("struct"); add("true"); - add("while"); + add("u1"); + add("u16"); + add("u32"); add("u8"); + add("while"); }}; @@ -85,9 +90,14 @@ public class Parser { Node.reset(); IterPeeps.reset(); TYPES.clear(); - TYPES.put("int",TypeInteger.BOT); - //TYPES.put("u8" ,TypeInteger.U8 ); - TYPES.put("flt",TypeFloat .BOT); + TYPES.put("bool",TypeInteger.U1 ); + TYPES.put("byte",TypeInteger.U8 ); + TYPES.put("flt" ,TypeFloat .BOT); + TYPES.put("int" ,TypeInteger.BOT); + TYPES.put("u1" ,TypeInteger.U1 ); + TYPES.put("u8" ,TypeInteger.U8 ); + TYPES.put("u16" ,TypeInteger.U16); + TYPES.put("u32" ,TypeInteger.U32); SCHEDULED = false; _lexer = new Lexer(source); _scope = new ScopeNode(); @@ -435,6 +445,9 @@ public class Parser { // Auto-widen int to float if( expr._type instanceof TypeInteger && t instanceof TypeFloat ) expr = new ToFloatNode(expr).peephole(); + // Auto-narrow wide ints to narrow ints + if( expr._type instanceof TypeInteger e0 && t instanceof TypeInteger t0 && !e0.isa(t) ) + expr = new AndNode(expr,new ConstantNode(TypeInteger.constant(t0._max-t0._min)).peephole()).peephole(); // Auto-deepen forward ref types Type e = expr._type; if( e instanceof TypeMemPtr tmp && tmp._obj._fields==null ) @@ -476,7 +489,27 @@ public class Parser { * * @return an expression {@link Node}, never {@code null} */ - private Node parseExpression() { return parseComparison(); } + private Node parseExpression() { return parseBitwise(); } + + /** + * Parse an bitwise expression + * + *
+     *     bitwise : compareExpr (('&' | '|' | '^') compareExpr)*
+     * 
+ * @return a bitwise expression {@link Node}, never {@code null} + */ + private Node parseBitwise() { + Node lhs = parseComparison(); + while( true ) { + if( false ) ; + else if( match("&") ) lhs = new AndNode(lhs,null); + else break; + lhs.setDef(2,parseComparison()); + lhs = lhs.peephole(); + } + return lhs; + } /** * Parse an expression of the form: @@ -640,6 +673,9 @@ public class Parser { else { Node val = parseExpression(); Type glb = base._fields[idx]._type; + // Auto-truncate when storing to narrow fields + if( !val._type.isa(glb) && glb instanceof TypeInteger t0) + val = new AndNode(val,new ConstantNode(TypeInteger.constant(t0._max-t0._min)).peephole()).peephole(); memAlias(alias, new StoreNode(name, alias,glb, memAlias(alias), expr, val, false).peephole()); return expr; // "obj.a = expr" returns the expression while updating memory } diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java new file mode 100644 index 00000000..1a3995d4 --- /dev/null +++ b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java @@ -0,0 +1,57 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +import java.util.BitSet; + +public class AndNode extends Node { + public AndNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "And"; } + + @Override public String glabel() { return "&"; } + + @Override + StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append("&"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeInteger i0 && + in(2)._type instanceof TypeInteger i1) { + if (i0.isConstant() && i1.isConstant()) + return TypeInteger.constant(i0.value()&i1.value()); + } + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // And of -1. We do not check for (0&x) because this will already + // canonicalize to (x&0) + if ( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==-1 ) + return rhs; + + // Move constants to RHS: con*arg becomes arg*con + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + // Do we have ((x & (phi cons)) & con) ? + // Do we have ((x & (phi cons)) & (phi cons)) ? + // Push constant up through the phi: x & (phi con0&con0 con1&con1...) + Node phicon = AddNode.phiCon(this,true); + if( phicon!=null ) return phicon; + + return null; + } + @Override Node copy(Node lhs, Node rhs) { return new AndNode(lhs,rhs); } +} diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java index d846fcef..382f78ae 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java @@ -93,10 +93,8 @@ public abstract class Node implements OutNode { @Override public final String toString() { return print(); } - // This is a *deep* print. This version will fail on cycles, which we will - // correct later when we can parse programs with loops. We print with a - // tik-tok style; the common _print0 calls the per-Node _print1, which - // calls back to _print0; + // This is a *deep* print. We print with a tik-tok style; the common + // _print0 calls the per-Node _print1, which calls back to _print0; public final String print() { return _print0(new StringBuilder(), new BitSet()).toString(); } diff --git a/chapter14/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/chapter14/src/main/java/com/seaofnodes/simple/type/TypeFloat.java index 0932a202..f40c7480 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/type/TypeFloat.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/type/TypeFloat.java @@ -54,7 +54,7 @@ public class TypeFloat extends Type { public StringBuilder typeName(StringBuilder sb) { if( this==TOP ) return sb.append("FltTop"); if( this==BOT ) return sb.append("FltBot"); - return sb.append("Int"); + return sb.append("Flt"); } @Override public boolean isHigh() { return this==TOP; } diff --git a/chapter14/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter14/src/main/java/com/seaofnodes/simple/type/TypeInteger.java index d3f9b66e..c84a4c13 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/type/TypeInteger.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -15,6 +15,8 @@ public class TypeInteger extends Type { public final static TypeInteger FALSE=ZERO; public final static TypeInteger TRUE= make(1,1); public final static TypeInteger U8 = make(0,255); + public final static TypeInteger U16 = make(0,65535); + public final static TypeInteger U32 = make(0,(1L<<32)-1); /** * Describes an integer *range* - everything from min to max; both min and @@ -39,16 +41,15 @@ public class TypeInteger extends Type { // FIXME this display format is problematic // In visualizer '#' gets prepended if its a constant @Override - public StringBuilder print(StringBuilder sb) { - if( this==TOP ) return sb.append("IntTop"); - if( this==BOT ) return sb.append("IntBot"); - if( isConstant() ) return sb.append(_min); - return sb.append("[").append(_min).append("-").append(_max).append("]"); - } + public StringBuilder print(StringBuilder sb) { return sb.append(str()); } @Override public String str() { if( this==TOP ) return "~int"; if( this==BOT ) return "int"; + if( this==BOOL) return ("bool"); + if( this==U8 ) return ("u8"); + if( this==U16 ) return ("u16"); + if( this==U32 ) return ("u32"); if( isConstant() ) return ""+_min; return "["+_min+"-"+_max+"]"; } -- cgit v1.2.3