summaryrefslogtreecommitdiff
path: root/chapter24/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-07 12:57:31 -0700
committerCliff Click <cliffc@acm.org>2026-10-07 12:57:31 -0700
commitaaec6f8136df6f7020bfc05f79ff5273adf73de1 (patch)
tree5df4aae069bd88dd09f45d957c85161e571b7a46 /chapter24/src
parent514b3147bf08817d17aacc492be255621209ec8b (diff)
downloadSimple-aaec6f8136df6f7020bfc05f79ff5273adf73de1.tar.gz
Simple-aaec6f8136df6f7020bfc05f79ff5273adf73de1.zip
flt->int conversion
Diffstat (limited to 'chapter24/src')
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/Parser.java4
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ToIntegerNode.java23
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/F8ToIARM.java21
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java1
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/F8ToIRISC.java19
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java1
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/F8ToIX86.java22
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java1
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java4
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java19
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter17bTest.java4
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Eval2.java2
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java2
13 files changed, 119 insertions, 4 deletions
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/Parser.java b/chapter24/src/main/java/com/seaofnodes/simple/Parser.java
index f28d0871..9cf565ac 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/Parser.java
@@ -707,6 +707,8 @@ public class Parser {
// Auto-narrow wide ints to narrow ints. For loads, emit code to force
// the loaded value to match the declared sign/zero bits. For stores,
// just force the type, acting "as if" the store silently truncates.
+ if( expr._type instanceof TypeFloat && t instanceof TypeInteger )
+ expr = peep(new ToIntegerNode(expr));
Type et = expr._type;
if( isLoad ) { expr = zsMask(expr,t); et = expr._type; }
else if( et instanceof TypeInteger && t instanceof TypeInteger ) et=t;
@@ -1643,6 +1645,8 @@ public class Parser {
// zero/sign extend. "i" is limited to either classic unsigned (min==0) or
// classic signed (min=minus-power-of-2); max=power-of-2-minus-1.
private Node zsMask(Node val, Type t ) {
+ if( val._type instanceof TypeFloat && t instanceof TypeInteger )
+ val = new ToIntegerNode(val).peephole();
if( !(val._type instanceof TypeInteger tval && t instanceof TypeInteger t0 && !tval.isa(t0)) ) {
if( !(val._type instanceof TypeFloat tval && t instanceof TypeFloat t0 && !tval.isa(t0)) )
return val;
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ToIntegerNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ToIntegerNode.java
new file mode 100644
index 00000000..df740202
--- /dev/null
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ToIntegerNode.java
@@ -0,0 +1,23 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.type.TypeInteger;
+
+// Truncate toward zero, saturating overflow; NaN converts to zero.
+public class ToIntegerNode extends Node {
+ public ToIntegerNode(Node lhs) { super(null,lhs); }
+ @Override public String label() { return "ToInteger"; }
+ @Override protected String format() { return "(int)%1"; }
+
+ @Override public Type compute() {
+ Type t = in(1)._type;
+ if( t.isHigh() ) return TypeInteger.TOP;
+ if( t instanceof TypeFloat tf && tf.isConstant() )
+ return TypeInteger.constant((long)tf.value());
+ return TypeInteger.BOT;
+ }
+
+ @Override public Node idealize() { return null; }
+ @Override Node copy(Node lhs, Node rhs) { return new ToIntegerNode(lhs); }
+}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/F8ToIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/F8ToIARM.java
new file mode 100644
index 00000000..31dcfc36
--- /dev/null
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/F8ToIARM.java
@@ -0,0 +1,21 @@
+package com.seaofnodes.simple.node.cpus.arm;
+
+import com.seaofnodes.isa.Arm64;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+
+public class F8ToIARM extends MachConcreteNode implements MachNode {
+ F8ToIARM(Node f8toi) { super(f8toi); }
+ @Override public String op() { return "cvti"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
+ @Override public void encoding( Encoding enc ) {
+ enc.add4(Arm64.floatToInteger(enc.reg(in(1))-arm.D_OFFSET,enc.reg(this)));
+ }
+
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p("(int)").p(code.reg(in(1)));
+ }
+
+}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
index f512f467..defec5ef 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
@@ -318,6 +318,7 @@ public class arm extends Machine {
case SubFNode subf -> new SubFARM(subf);
case SubNode sub -> sub(sub);
case ToFloatNode tfn -> new I2F8ARM(tfn);
+ case ToIntegerNode cvt -> new F8ToIARM(cvt);
case XorNode xor -> xor(xor);
case LoopNode loop -> new LoopNode(loop);
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/F8ToIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/F8ToIRISC.java
new file mode 100644
index 00000000..a56ad216
--- /dev/null
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/F8ToIRISC.java
@@ -0,0 +1,19 @@
+package com.seaofnodes.simple.node.cpus.riscv;
+
+import com.seaofnodes.isa.RiscV;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+
+public class F8ToIRISC extends MachConcreteNode implements MachNode {
+ F8ToIRISC(Node f8toi) {super(f8toi);}
+ @Override public String op() { return "cvti"; }
+ @Override public RegMask regmap(int i) { assert i==1; return riscv.FMASK; }
+ @Override public RegMask outregmap() { return riscv.WMASK; }
+ @Override public void encoding( Encoding enc ) {
+ RiscV.floatToInteger(enc,enc.reg(this),enc.reg(in(1))-riscv.F_OFFSET);
+ }
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p("(int)").p(code.reg(in(1)));
+ }
+}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index 6be0376a..78d21f3b 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -240,6 +240,7 @@ public class riscv extends Machine {
case SubFNode subf -> new SubFRISC(subf);
case SubNode sub -> sub(sub);
case ToFloatNode tfn -> i2f8(tfn);
+ case ToIntegerNode cvt -> new F8ToIRISC(cvt);
case XorNode xor -> xor(xor);
case LoopNode loop -> new LoopNode(loop);
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/F8ToIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/F8ToIX86.java
new file mode 100644
index 00000000..a79a1017
--- /dev/null
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/F8ToIX86.java
@@ -0,0 +1,22 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.isa.X86;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+
+public class F8ToIX86 extends MachConcreteNode implements MachNode {
+ F8ToIX86(Node f8toi ) { super(f8toi); }
+ @Override public String op() { return "cvti"; }
+ @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.XMASK; }
+ @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
+
+ @Override public void encoding( Encoding enc ) {
+ X86.floatToInteger(enc,enc.reg(this),enc.reg(in(1))-x86_64_v2.XMM_OFFSET);
+ }
+
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p("(int)").p(code.reg(in(1)));
+ }
+}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index 4beef793..e283bc8f 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -287,6 +287,7 @@ public class x86_64_v2 extends Machine {
case SubFNode subf -> new SubFX86(subf);
case SubNode sub -> sub(sub);
case ToFloatNode tfn -> i2f8(tfn);
+ case ToIntegerNode cvt -> new F8ToIX86(cvt);
case XCtrlNode x -> new ConstantNode(Type.XCONTROL);
case XorNode xor -> xor(xor);
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index 8e9aaed6..041e0d06 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -124,8 +124,8 @@ struct N { !N? !next; int i; };
n.i = 3.14;
return n.i;
""");
- try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Type 3.14 is not of declared type i64",e.getMessage()); }
+ code.parse().opto().typeCheck();
+ assertEquals("3",Eval2.eval(code,0));
}
@Test
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
index 009beb0b..23d0ef37 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
@@ -7,6 +7,25 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class Chapter14FloatTest {
+ @Test public void testNumericAssignments() {
+ String[][] tests = {
+ {"int rounded=17.3/2.5; return rounded;", "6", "6"},
+ {"int rounded=arg/2.5; return rounded;", "6", "-6"},
+ {"int rounded=0; rounded=arg/2.5; return rounded;", "6", "-6"},
+ {"i8 rounded=arg*16.0; return rounded;", "16", "-16"},
+ {"int rounded=1e100; return rounded;", "9223372036854775807", "9223372036854775807"},
+ {"int rounded=-1e100; return rounded;", "-9223372036854775808", "-9223372036854775808"},
+ {"int rounded=1e300*1e300-1e300*1e300; return rounded;", "0", "0"},
+ {"f32 rounded=arg+16777216.0; return rounded;", "1.6777232E7", "1.6777199E7"}
+ };
+ for( String[] test : tests ) {
+ var code = new CodeGen(test[0]).parse().opto().typeCheck();
+ assertEquals(test[0],test[1],Eval2.eval(code,17));
+ assertEquals(test[0],test[2],Eval2.eval(code,-17));
+ }
+ }
+
+
@Test public void testSubZeroFloat() {
var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck();
// Compare strings so +0.0 and -0.0 remain distinct.
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter17bTest.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
index 813fc4c2..59bd3b0c 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
@@ -123,8 +123,8 @@ return s.x;
@Test public void testInt10() {
CodeGen code = new CodeGen("flt x = 1.5; x++; int i = x; return i;");
- try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Type 2.5f is not of declared type i64",e.getMessage()); }
+ code.parse().opto().typeCheck();
+ assertEquals("2",Eval2.eval(code,0));
}
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java
index e0d56399..98e0f18a 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java
@@ -283,6 +283,8 @@ public abstract class Eval2 {
case StoreNode st -> store(st);
case SubNode sub -> x(sub.in(1)) - x(sub.in(2));
case SubFNode sbf -> d(sbf.in(1)) - d(sbf.in(2));
+ case RoundF32Node rnd -> (double)(float)d(rnd.in(1));
+ case ToIntegerNode cvt -> (long)d(cvt.in(1));
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/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index 1c116162..20aac367 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -298,6 +298,8 @@ public class Evaluator {
case OrNode or -> vall(or .in(1)) | vall(or .in(2));
case XorNode xor -> vall(xor.in(1)) ^ vall(xor.in(2));
case CastNode cast -> val(cast.in(1));
+ case RoundF32Node rnd -> (double)(float)vald(rnd.in(1));
+ case ToIntegerNode cvt -> (long)vald(cvt.in(1));
case ToFloatNode cast -> (double)vall(cast.in(1));
case LoadNode load -> load(load);
case StoreNode store -> store(store);