summaryrefslogtreecommitdiff
path: root/src/test/java/com/seaofnodes
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-21 14:18:23 -0700
committerCliff Click <cliffc@acm.org>2025-07-03 09:50:14 -0700
commit018379b0cf4e286ceacb1e39f34dd80f770e381e (patch)
treed88eae2d5e2d9609f271ec78fb60aaf08c5aaee5 /src/test/java/com/seaofnodes
parent49534ffa88fedb3a4ebc42094e9edb27d456e6d6 (diff)
downloadSimple-018379b0cf4e286ceacb1e39f34dd80f770e381e.tar.gz
Simple-018379b0cf4e286ceacb1e39f34dd80f770e381e.zip
Chapter 22: A Hello, World!linear-chapter22
Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Diffstat (limited to 'src/test/java/com/seaofnodes')
-rw-r--r--src/test/java/com/seaofnodes/simple/BrainFuckTest.java2
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter01Test.java6
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter09Test.java9
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter10Test.java2
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter13Test.java7
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter15Test.java6
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter16Test.java4
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter17Test.java8
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter18Test.java17
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter19Test.java7
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter20Test.java7
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter21Test.java8
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter22Test.java240
-rw-r--r--src/test/java/com/seaofnodes/simple/Eval2.java22
-rw-r--r--src/test/java/com/seaofnodes/simple/EvalArm64.java1156
-rw-r--r--src/test/java/com/seaofnodes/simple/EvalRisc5.java28
-rw-r--r--src/test/java/com/seaofnodes/simple/Simple.java246
-rw-r--r--src/test/java/com/seaofnodes/simple/TestC.java97
-rw-r--r--src/test/java/com/seaofnodes/simple/TypeTest.java16
-rw-r--r--src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java2
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/echo.smp3
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/helloWorld.smp3
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/jig.smp4
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/person.smp2
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/riscv_load.smp4
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp4
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp5
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp4
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp4
-rw-r--r--src/test/java/com/seaofnodes/simple/progs/store_peep.smp3
30 files changed, 1116 insertions, 810 deletions
diff --git a/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 2733620e..1e1a1dc3 100644
--- a/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -16,7 +16,7 @@ public class BrainFuckTest {
String brain_fuck = "Hello World!\n";
TestC.run("brain_fuck", brain_fuck, 40);
- EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 44, false);
+ EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 28, false);
int trap = R5.step(100000);
assertEquals(0,trap);
int ptr = (int)R5.regs[riscv.A0];
diff --git a/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index cddbdfcf..ac9adacc 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -25,9 +25,9 @@ public class Chapter01Test {
public void testZero() {
CodeGen code = new CodeGen("return 0;");
code.parse();
- for( Node use : code._start._outputs )
- if( use instanceof ConstantNode con && con._type instanceof TypeInteger )
- assertEquals(TypeInteger.constant(0),con._type);
+ Node use = code.expr();
+ if( use instanceof ConstantNode con && con._type instanceof TypeInteger )
+ assertEquals(TypeInteger.constant(0),con._type);
}
@Test
diff --git a/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/src/test/java/com/seaofnodes/simple/Chapter09Test.java
index 401f346f..d4d02aa9 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter09Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter09Test.java
@@ -128,14 +128,14 @@ while(v1+arg) {
}
""");
code.parse().opto();
- assertEquals("return 0;", code.print());
+ assertEquals("return Top;", code.print());
}
@Test
public void testWhile0() {
- CodeGen code = new CodeGen("while(0) continue; if(0) arg=0;");
+ CodeGen code = new CodeGen("while(0) continue; if(0) arg=0; return arg;");
code.parse().opto();
- assertEquals("return 0;", code.print());
+ assertEquals("return arg;", code.print());
}
@Test
@@ -145,6 +145,7 @@ if(0) while(0) {
int arg=arg;
while(0) {}
}
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
@@ -255,7 +256,7 @@ while(0==1) while(v0)
v0=1+v0;
""");
code.parse().opto();
- assertEquals("return 0;", code.print());
+ assertEquals("Stop[ ]", code.print());
}
@Test
diff --git a/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index 1253e4a6..712704db 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -304,6 +304,7 @@ if(0) {
v0=v2;
}
}
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
@@ -378,6 +379,7 @@ while(0) {}
}
} }
}
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
diff --git a/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/src/test/java/com/seaofnodes/simple/Chapter13Test.java
index 6bf45a22..a19f85e3 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter13Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter13Test.java
@@ -130,15 +130,15 @@ return n.i;
@Test
public void testNullRef4() {
- CodeGen code = new CodeGen("-null-5/null-5;");
+ CodeGen code = new CodeGen("return -null-5/null-5;");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot '+' null",e.getMessage()); }
}
@Test public void testNullRef5() {
CodeGen code = new CodeGen("return null+42;");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot '+' null",e.getMessage()); }
}
@Test
@@ -146,6 +146,7 @@ return n.i;
CodeGen code = new CodeGen(
"""
struct S{};
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
diff --git a/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index 8b138b46..a98e62d8 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -253,10 +253,10 @@ return new flt;
public void testBad1() {
CodeGen code = new CodeGen(
"""
-int is = new int[2];
+flt is = new int[2];
""");
try { code.parse().opto(); fail(); }
- catch( Exception e ) { assertEquals("Type *[int] is not of declared type int",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Type *[int] is not of declared type flt",e.getMessage()); }
}
@Test
@@ -323,6 +323,7 @@ while(0) {}
u32 v7=0;
int v8=0;
while(0<--1>>>---(v7*0==v8)) {}
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
@@ -347,6 +348,7 @@ else {
}
}
}
+return 0;
""");
code.parse().opto();
assertEquals("return 0;", code.print());
diff --git a/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index 930624e5..58bb4148 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -128,7 +128,7 @@ p.x++;
return p;
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test
@@ -140,7 +140,7 @@ p.x++;
return p;
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test
diff --git a/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index 78515083..bdeb645c 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -172,13 +172,13 @@ return s.x;
@Test public void testVar6() {
CodeGen code = new CodeGen("struct S{int x;}; S s=new S; s.x++; return s.x; // Error initializer so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar7() {
CodeGen code = new CodeGen("struct S{int x;}; S s=new S{x=3;}; s.x++; return s.x; // Error initializer so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar8() {
@@ -198,7 +198,7 @@ return s.x;
@Test public void testVar10() {
CodeGen code = new CodeGen("struct S{int x;}; val s=new S; s.x++; return s.x; // Error, has val so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar11() {
@@ -216,7 +216,7 @@ val xfoo = foo; // Throw away mutability
xfoo.bar.x++; // Error, cannot mutate through xfoo
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar12() {
diff --git a/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index c0e28412..00d41a23 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -33,7 +33,7 @@ while(arg--) {
}
return a;
""");
- code.parse().opto().typeCheck().GCM();
+ code.parse().opto().typeCheck();
assertEquals("return Phi(Loop,1,Phi(Loop,2,Phi_a));", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
assertEquals("2", Eval2.eval(code, 1));
@@ -78,7 +78,7 @@ var sq = { int x ->
return sq(arg)+sq(3);
""");
code.driver(Phase.LocalSched);
- assertEquals("Stop[ return (#2+#2); return (Parm_x(sq,int)*x); ]", code._stop.toString());
+ assertEquals("Stop[ return (Parm_x(sq,int)*x); return (#2+#2); ]", code._stop.toString());
assertEquals("13", Eval2.eval(code, 2));
}
@@ -116,7 +116,7 @@ var fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(3);
""");
code.parse().opto();
- assertEquals("Stop[ return #2; return (Parm_x($fun1,int,3)*x); return (Parm_x($fun2,int,3)<<1); ]", code._stop.toString());
+ assertEquals("Stop[ return (Parm_x($fun2,int,3)<<1); return (Parm_x($fun1,int,3)*x); return #2; ]", code._stop.toString());
assertEquals("6", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
}
@@ -126,7 +126,7 @@ return fcn(3);
public void testFcn5() {
CodeGen code = new CodeGen("val fact = { int x -> x <= 1 ? 1 : x*fact(x-1); }; return fact(arg);");
code.parse().opto().typeCheck();
- assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,int,arg,(x-1))*#2)); ]", code._stop.toString());
+ assertEquals("Stop[ return Phi(Region,1,(Parm_x(fact,int,arg,(x-1))*#2)); return #2; ]", code._stop.toString());
assertEquals( "1", Eval2.eval(code, 0));
assertEquals( "1", Eval2.eval(code, 1));
assertEquals( "2", Eval2.eval(code, 2));
@@ -158,7 +158,7 @@ val g = {->2;};
return 2;
""");
code.parse().opto().typeCheck().GCM();
- assertEquals("Stop[ return 1; return 1; return 2; ]", code._stop.toString());
+ assertEquals("Stop[ return 2; return 1; return 1; ]", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -176,7 +176,7 @@ for(;;) {
}
""");
code.driver(Phase.LocalSched);
- assertEquals("Stop[ return #2; return Parm_i(x,int); ]", code._stop.toString());
+ assertEquals("Stop[ return Parm_i(x,int); return #2; ]", code._stop.toString());
assertEquals("3", Eval2.eval(code, 0));
}
@@ -214,7 +214,7 @@ val fcn = { Person?[] ps, int x ->
var ps = new Person?[2];
ps[0] = new Person;
ps[1] = new Person;
-fcn(ps,1);
+return fcn(ps,1);
""");
code.driver(Phase.LocalSched);
assertEquals("return 0;", code._stop.toString());
@@ -249,6 +249,7 @@ for(;;) {
if (i2i(2) == arg) break;
i2i = null;
}
+return 0;
""");
try { code.parse().opto().typeCheck(); fail(); }
catch( Exception e ) { assertEquals("Might be null calling { int -> int #1}?",e.getMessage()); }
@@ -347,7 +348,7 @@ if (i2i) return i2i(arg);
return f2f(o)(1);
""");
code.driver(Phase.LocalSched);
- assertEquals("Stop[ return Phi(Region,#2,#2); return Parm_i(o,int); ]", code._stop.toString());
+ assertEquals("Stop[ return Parm_i(i2i.o,int); return Phi(Region,#2,#2); ]", code._stop.toString());
assertEquals("1", Eval2.eval(code, 2));
}
diff --git a/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/src/test/java/com/seaofnodes/simple/Chapter19Test.java
index bce75c81..b8ef22d7 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter19Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter19Test.java
@@ -25,7 +25,7 @@ return 0;
public void testString() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp"));
CodeGen code = new CodeGen(src).parse().opto().typeCheck().GCM().localSched();
- assertEquals("Stop[ return Phi(Region,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); return Phi(Region,1,0,0,1); ]", code._stop.toString());
+ assertEquals("Stop[ return Phi(Region,1,0,0,1); return Phi(Region,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code._stop.toString());
//assertEquals("-4898613127354160978", Eval2.eval(code, 2));
}
@@ -271,6 +271,7 @@ for( int i=0; i<A#; i++ )
A[i] = i;
for( int i=0; i<A#; i++ )
B[i] += A[i];
+return 0;
""");
code.driver(Phase.LocalSched,"x86_64_v2", "SystemV");
assertEquals("return 0;", code.print());
@@ -315,7 +316,7 @@ val fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(2)*10 + fcn(3);
""");
code.driver(Phase.LocalSched,"x86_64_v2", "SystemV");
- assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun1,int),x); return (shli,Parm_x($fun2,int)); ]", code.print());
+ assertEquals("Stop[ return (shli,Parm_x($fun2,int)); return (mul,Parm_x($fun1,int),x); return (add,#2,(muli,#2)); ]", code.print());
}
@Test
@@ -326,6 +327,6 @@ val sq = { int x -> x*x; };
return sq(arg) + sq(3);
""");
code.driver(Phase.LocalSched,"x86_64_v2", "SystemV");
- assertEquals("Stop[ return (add,#2,#2); return (mul,Parm_x(sq,int),x); ]", code.print());
+ assertEquals("Stop[ return (mul,Parm_x(sq,int),x); return (add,#2,#2); ]", code.print());
}
}
diff --git a/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 5b33d1e7..f442ae1a 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -63,9 +63,10 @@ val sqrt = { int x ->
guess = next;
}
};
-return sqrt(arg) + sqrt(arg+2);
+int cast_int = arg+2;
+return sqrt(arg) + sqrt(cast_int);
""";
- testCPU(src,"x86_64_v2", "Win64" ,23,null);
+ testCPU(src,"x86_64_v2", "Win64" ,55,null);
testCPU(src,"riscv" , "SystemV",19,null);
testCPU(src,"arm" , "SystemV",19,null);
}
@@ -103,7 +104,7 @@ return sqrt(arg) + sqrt(arg+2);
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp"));
testCPU(src,"x86_64_v2", "SystemV", 9,null);
testCPU(src,"riscv" , "SystemV", 5,null);
- testCPU(src,"arm" , "SystemV", 6,null);
+ testCPU(src,"arm" , "SystemV", 3,null);
}
@Test
diff --git a/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index d8a5cebc..77d1e337 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -39,7 +39,7 @@ public class Chapter21Test {
}
@Test public void testInfinite() {
- String src = "struct S { int i; }; S !s = new S; while(1) s.i++;";
+ String src = "struct S { int i; }; S !s = new S; while(1) s.i++; return s.i;";
testCPU(src,"x86_64_v2", "SystemV",0,"return Top;");
testCPU(src,"riscv" , "SystemV",2,"return Top;");
testCPU(src,"arm" , "SystemV",2,"return Top;");
@@ -66,7 +66,7 @@ public class Chapter21Test {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp"));
testCPU(src,"x86_64_v2", "SystemV", 9,null);
testCPU(src,"riscv" , "SystemV", 5,null);
- testCPU(src,"arm" , "SystemV", 6,null);
+ testCPU(src,"arm" , "SystemV", 3,null);
}
@Test public void testStringExport() throws IOException {
@@ -150,14 +150,14 @@ public class Chapter21Test {
String fib = "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]";
TestC.run("fib", fib, 24);
- EvalRisc5 R5 = TestRisc5.build("fib", 9, 16, false);
+ EvalRisc5 R5 = TestRisc5.build("fib", 9, 17, false);
int trap = R5.step(100);
assertEquals(0,trap);
// Return register A0 holds fib(8)==55
assertEquals(55,R5.regs[riscv.A0]);
// arm
- EvalArm64 A5 = TestArm64.build("fib", 9, 16, false);
+ EvalArm64 A5 = TestArm64.build("fib", 9, 17, false);
int trap_arm = A5.step(100);
assertEquals(0,trap_arm);
// Return register X0 holds fib(8)==55
diff --git a/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/src/test/java/com/seaofnodes/simple/Chapter22Test.java
new file mode 100644
index 00000000..394ba336
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -0,0 +1,240 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.seaofnodes.simple.node.cpus.arm.arm;
+import com.seaofnodes.simple.node.cpus.riscv.riscv;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Chapter22Test {
+
+ @Test @Ignore
+ public void testJig() throws IOException {
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp"));
+ //String src = Files.readString(Path.of("docs/examples/BubbleSort.smp"));
+ testCPU(src,"x86_64_v2", "Win64" ,-1,null);
+ testCPU(src,"riscv" , "SystemV",-1,null);
+ testCPU(src,"arm" , "SystemV",-1,null);
+ }
+
+ static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) {
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os);
+ int delta = spills>>3;
+ if( delta==0 ) delta = 1;
+ if( spills != -1 )
+ assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);
+ if( stop != null )
+ assertEquals(stop, code._stop.toString());
+ return code;
+ }
+
+
+ static int testCPUSize( String src, String cpu, String os, int spills, String stop ) {
+ return testCPU(src,cpu,os,spills,stop)._encoding._bits.size();
+ }
+
+ // Should not fold away
+ @Test public void testSextFail() throws IOException {
+ String src = """
+struct Person { i32 age;};
+Person !p = new Person;
+p.age = (arg<<17)>>17;
+return 0;
+""";
+ assertEquals(46, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;"));
+ assertEquals(60, testCPUSize(src, "riscv","SystemV",4,"return 0;"));
+ assertEquals(56, testCPUSize(src, "arm","SystemV",4,"return 0;"));
+
+ // do assertEquals here
+ EvalRisc5 R5 = TestRisc5.build("sext_str_not_fold_away", 0, 4, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+
+ EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away", 0, 4, false);
+ trap = A5.step(100);
+ assertEquals(0,trap);
+
+ }
+
+ // Should not fold away
+ @Test public void testSextFail2() throws IOException {
+ String src = """
+
+ struct Person { i32 age;};
+ Person !p = new Person;
+ p.age = (arg<<48)>>48;
+ return 0;
+ """;
+
+ EvalRisc5 R5 = TestRisc5.build("sext_str_not_fold_away_2", 0, 4, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+
+ EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away_2", 0, 4, false);
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+
+ assertEquals(46, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;"));
+ assertEquals(60, testCPUSize(src, "riscv","SystemV",4,"return 0;"));
+ assertEquals(56, testCPUSize(src, "arm","SystemV",4,"return 0;"));
+
+ }
+
+ // Should fold away
+ @Test public void testSextSuccess() throws IOException {
+ String src = """
+// Should fold away sign extend
+struct Person { i8 age;};
+Person !p = new Person;
+p.age = (arg<<48)>>48;
+return 0;
+ """;
+
+ EvalRisc5 R5 = TestRisc5.build("sext_str_fold_away", 0, 5, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+
+ EvalArm64 A5 = TestArm64.build("sext_str_fold_away", 0, 5, false);
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+
+ assertEquals(41, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;"));
+ assertEquals(56, testCPUSize(src, "riscv","SystemV",5,"return 0;"));
+ assertEquals(52, testCPUSize(src, "arm","SystemV",5,"return 0;"));
+ // do assertEquals here
+ }
+
+
+ // Int now is changed to 4 bytes.
+ @Test public void testPerson() throws IOException {
+ String person = "6\n";
+ TestC.run("person", person, 0);
+
+ // Memory layout starting at PS:
+ int ps = 1<<16; // Person array pointer starts at heap start
+ // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8
+ // P0 = { age } // sizeof=8
+ int p0 = ps+4*8+0*8;
+ // P1 = { age } // sizeof=8
+ int p1 = ps+4*8+1*8;
+ // P2 = { age } // sizeof=8
+ int p2 = ps+4*8+2*8;
+ EvalRisc5 R5 = TestRisc5.build("person", ps, 0, false);
+ R5.regs[riscv.A1] = 1; // Index 1
+ R5.st8(ps,3); // Length
+ R5.st8(ps+1*8,p0);
+ R5.st8(ps+2*8,p1);
+ R5.st8(ps+3*8,p2);
+ R5.st8(p0, 5); // age= 5
+ R5.st8(p1,17); // age=17
+ R5.st8(p2,60); // age=60
+
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals( 5+0,R5.ld8(p0));
+ assertEquals(17+1,R5.ld8(p1));
+ assertEquals(60+0,R5.ld8(p2));
+
+ EvalArm64 A5 = TestArm64.build("person", ps, 0, false);
+ A5.regs[arm.X1] = 1; // Index 1
+ A5.st8(ps, 3);
+ A5.st8(ps+1*8,p0);
+ A5.st8(ps+2*8,p1);
+ A5.st8(ps+3*8,p2);
+ A5.st8(p0, 5); // age= 5
+ A5.st8(p1,17); // age=17
+ A5.st8(p2,60); // age=60
+
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+ assertEquals( 5+0, A5.ld8(p0));
+ assertEquals(17+1, A5.ld8(p1));
+ assertEquals(60+0, A5.ld8(p2));
+ }
+
+ @Test
+ public void testCoRecur() {
+ String src = """
+struct A { B? b; C? c; i64 ax; val az = x*2; };
+struct B { A? a; C? c; f32 bx; val bz = x*3; };
+struct C { A? a; B? b; f64 cx; val cz = x*x; };
+A !aa = new A{ ax=17; };
+B !bb = new B{ bx=3.14; a = aa; };
+C !cc = new C{ cx=2.73; a = aa; b = bb; };
+aa.b = bb;
+aa.c = cc;
+bb.c = cc;
+val x = 5; // aa.az; // Error to self-define forward ref
+return cc.cz;
+""";
+ CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ assertEquals("return 25;", code._stop.toString());
+ assertEquals("25", Eval2.eval(code, 0));
+ }
+
+ @Test
+ public void testHelloWorld() throws IOException {
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp"));
+ TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("Hello, World!",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("helloWorld", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("Hello, World!",arm._stdout.toString());
+ }
+
+ @Test
+ public void testFinalArray() {
+ String src = """
+int N=4;
+i32[] !is = new i32[N];
+for( int i=0; i<N; i++ )
+ is[i] = i*i;
+val sum = { i32[~] is -> // final array
+ int sum=0;
+ for( int i=0; i<is#; i++ )
+ sum += is[i];
+ return sum;
+};
+return sum(is);
+""";
+ CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ assertEquals("return Phi(Loop,0,(Phi_sum+.[]));", code._stop.toString());
+ assertEquals("14", Eval2.eval(code, 0));
+ }
+
+
+ @Test @Ignore
+ public void testEcho() throws IOException {
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/echo.smp"));
+ TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/echo","","",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("echo", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("echo", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ }
+
+
+}
diff --git a/src/test/java/com/seaofnodes/simple/Eval2.java b/src/test/java/com/seaofnodes/simple/Eval2.java
index ecea97dd..86f0e9db 100644
--- a/src/test/java/com/seaofnodes/simple/Eval2.java
+++ b/src/test/java/com/seaofnodes/simple/Eval2.java
@@ -114,11 +114,10 @@ public abstract class Eval2 {
public static String eval( CodeGen code, long arg ) { return eval(code,arg,1000); }
public static String eval( CodeGen code, long arg, int timeout ) {
+ if( code._start.uctrl()==null ) return ""; // The empty program
SB trace = null; // new SB(); // TRACE, set to null for off, new SB() for on
// Force local scheduling phase
- if( code._phase.ordinal() < CodeGen.Phase.TypeCheck .ordinal() ) code.typeCheck();
- if( code._phase.ordinal() < CodeGen.Phase.Schedule .ordinal() ) code.GCM();
- if( code._phase.ordinal() < CodeGen.Phase.LocalSched.ordinal() ) code.localSched();
+ code.driver(CodeGen.Phase.LocalSched);
// Set global, so don't have to pass everywhere
CODE = code;
@@ -290,9 +289,9 @@ public abstract class Eval2 {
// Fetch without unboxing, searching up-Frame
static Object val( Node n ) { return F.get(n); }
// Fetch and unbox as primitive long
- static long x( Node n ) { Object d = F.get(n); return d==null ? 0 : (Long) F.get(n); }
+ static long x( Node n ) { Object d = F.get(n); return d==null ? 0 : (Long)d; }
// Fetch and unbox as primitive double
- static double d( Node n ) { Object d = F.get(n); return d==null ? 0 : (Double)F.get(n); }
+ static double d( Node n ) { Object d = F.get(n); return d==null ? 0 : (Double)d; }
// Fetch and unbox a function constant
static TypeFunPtr tfp(Node n) { return (TypeFunPtr)F.get(n); }
// Fetch and unbox a closure
@@ -348,10 +347,19 @@ public abstract class Eval2 {
}
private static Object load( LoadNode ld ) {
- TypeMemPtr tmp = (TypeMemPtr)ld.ptr()._type;
- Object[] fs = (Object[])val(ld.ptr());
+ Object f = val(ld.ptr());
+ // Check for dense constant array
+ if( f instanceof TypeMemPtr tmp ) {
+ assert tmp._obj._con != TypeConAry.BOT;
+ if( ld._name.equals("#") )
+ return (long)tmp._obj._con.len();
+ int idx = offToIdx(x(ld.off()),tmp._obj);
+ return tmp._obj._con.at(idx);
+ }
+ Object[] fs = (Object[])f;
if( ld._name.equals("#") )
return (long)fs.length;
+ TypeMemPtr tmp = (TypeMemPtr)ld.ptr()._type;
int idx = tmp._obj.isAry()
? offToIdx(x(ld.off()),tmp._obj)
: tmp._obj.find(ld._name);
diff --git a/src/test/java/com/seaofnodes/simple/EvalArm64.java b/src/test/java/com/seaofnodes/simple/EvalArm64.java
index 3ea9bea0..981799bb 100644
--- a/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ b/src/test/java/com/seaofnodes/simple/EvalArm64.java
@@ -2,6 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.cpus.arm.arm;
+import java.io.ByteArrayOutputStream;
public class EvalArm64 {
// Memory image, always 0-based
@@ -13,9 +14,13 @@ public class EvalArm64 {
final double[] fregs;
int _pc;
- int SENTINEL_CALLOC = -4;
+
// Start of free memory for allocation
int _heap;
+
+ // Standard out and err streams
+ ByteArrayOutputStream _stdout, _stderr;
+
// Cycle counters
int _cycle;
@@ -38,8 +43,7 @@ public class EvalArm64 {
public int ld1s(int x) { return _buf[x ] ; }
public int ld1z(int x) { return _buf[x ]&0xFF; }
public int ld2s(int x) { return ld1z(x) | ld1s(x+1)<< 8; }
- public int ld2z(int x) {
- return ld1z(x) | ld1z(x+1)<< 8; }
+ public int ld2z(int x) { return ld1z(x) | ld1z(x+1)<< 8; }
public int ld4s(int x) { return ld2z(x) | ld2s(x+2)<<16; }
public long ld8 (int x) { return (long)ld4s(x)&0xFFFFFFFFL | ((long)ld4s(x+4))<<32; }
@@ -81,652 +85,656 @@ public class EvalArm64 {
int rdid = ir & 0x1f;
// [31:24]
int opcode1 = (ir >> 24) & 0xFF;
- // [31:26]
- int opcode2 = (ir >> 26) & 0x3F;
-
- switch(opcode2) {
- case 5: {
- //b
- int imm26 = ir << 6 >> 6;
-
- pc = pc + (imm26 * 4) - 4;
- // won't hit pc += 4 at the bottom because continue
- // do it manually
- pc += 4;
+
+ // for the opcode we just match for bits[31:24];
+ switch( opcode1 ) {
+ case 0x14, 0x15, 0x16, 0x17: { //b
+ int imm26 = ir << 6 >> 6;
+ pc = pc + (imm26 * 4) - 4;
+ rdid = -1;
+ break;
+ }
+ case 0x1E: { // floats
+ is_f = true;
+ int rs1 = (ir >> 5) & 0x1F;
+ int rs2 = (ir >> 16) & 0x1F;
+
+ int op = (ir >> 10) & 0x3F;
+ switch(op) {
+ case 16: frval = fregs[rs1]; break; // fmov
+ case 10:frval = fregs[rs1] + fregs[rs2]; break; // fadd
+
+ case 6: if (fregs[rs2] == 0) frval = 0; else frval = fregs[rs1] / fregs[rs2]; break; // fdiv
+ case 8: {
+ // fcmp
+ double lhs = fregs[rs1];
+ double rhs = fregs[rs2];
+
+ Z = (lhs == rhs);
+ N = (lhs < rhs);
+ C = lhs >= rhs;
+ V = Double.isNaN(lhs) || Double.isNaN(rhs);
rdid = -1;
- continue ;
- }
- case 0x25: {
- // bl (just calloc)
- rval = pc + 4;
- regs[arm.X30] = rval;
- if(pc + 4 == 0) {
- regs[rdid] = rval;
- break outer;
- }
- int imm26 = (ir & 0x03FFFFFF);
- int imm = (imm26 << 6) >> 6;
- pc = pc + (imm << 2) ;
- if (pc == SENTINEL_CALLOC) {
- long size = regs[arm.X0]*regs[arm.X1];
- regs[arm.X0] = _heap;
- _heap += (int)size;
- // unwind pc
- pc = (int)rval;
- }
- continue;
+
+ break;
+ }
+ case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul
+ case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub
+ default: trap = (2+1);
}
+ break;
}
- // for the opcode we just match for bits[31:24];
- switch(opcode1) {
- case 0xD2: {
- // movz
- // get immediate
- rval = (ir >> 5) & 0x7FFF;
- break;
+
+ case 0x38: {
+ // STRB/LDRB(register)
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch( ir >> 21 & 0x7 ) {
+ case 0x1 -> { // store
+ if( opcode1 == arm.OP_STORE_R_8 ) st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ else trap = (2+1);
+ rdid = -1;
}
- case 0x38: {
- // STRB/LDRB(register)
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- // store
- if(opcode1 == arm.OP_STORE_R_8) {
- st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OP_LOAD_R_8) {
- rval = ld1s((int)regs[rn] + (int)regs[rm]);
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
+ case 0x3 -> { // load
+ if( opcode1 == arm.OP_LOAD_R_8 ) rval = ld1s((int)regs[rn] + (int)regs[rm]);
+ else trap = (2+1);
+ }
+ default -> trap = (2+1);
+ }
+ break;
+ }
+ case 0x39: {
+ // STRB/LDRB(immediate)
+ // str/ldr(immediate)
+ // rn
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_8) {
+ st1((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+ rdid = -1;
+
break;
}
- case 0x39: {
- // STRB/LDRB(immediate)
- // str/ldr(immediate)
- // rn
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
-
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_8) {
- st1((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
- rdid = -1;
-
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_8) {
- rval = ld1s((int)rval);
- } else trap = (2+1);
- rdid = -1;
- break;
- }
- default: trap = (2+1);
- }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_8) {
+ rval = ld1s((int)rval);
+ } else trap = (2+1);
+ rdid = -1;
break;
}
- case 0x78: {
- // STRH/LDRH(register)
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- // store
- if(opcode1 == arm.OP_STORE_R_16) {
- st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OP_LOAD_R_16) {
- rval = ld1s((int)regs[rn] + (int)regs[rm]);
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x54: {
+ // b.cond
+ int imm19 = ir << 8 >> 13;
+ imm19 = pc + (imm19 * 4) - 4;
+ rdid = -1;
+
+ switch(ir & 0xF) {
+ case 0x0: if(Z) pc = imm19; break; // eq
+ case 0x1: if(!Z) pc = imm19; break; // ne
+ case 0x2: if(C) pc = imm19; break; // cs
+ case 0x3: if(!C) pc = imm19; break;
+ case 0x4: if(N) pc = imm19; break; // mi
+ case 0x5: if(!N) pc = imm19; break; // pl
+ case 0x6: if(V) pc = imm19; break; // vs
+ case 0x7: if(!V) pc = imm19; break; // vc
+ case 0x8: if(C && !Z) pc = imm19; break; // hi
+ case 0x9: if(!C || Z) pc = imm19; break; // ls
+ case 0xA: if(N == V) pc = imm19; break; // ge
+ case 0xB: if(N != V) pc = imm19; break; // lt
+ case 0xC: if(!Z && N == V) pc = imm19; break; // gt
+ case 0xD: if(Z || N != V) pc = imm19; break; // le
+ case 0xE: pc = imm19; break; // always executed(al)
+ default: trap = (2+1);
+ }
+ break;
+ }
+
+ case 0x5c: {
+ // ldr
+ is_f = true;
+ // address = delta
+ int address = ir << 8 >> 13;
+ address *= 4;
+ if(address >= _buf.length-3) trap = (5 + 1);
+ frval = ld8f(pc + address);
+ break;
+ }
+
+ case 0x78: {
+ // STRH/LDRH(register)
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ // store
+ if(opcode1 == arm.OP_STORE_R_16) {
+ st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
}
+ rdid = -1;
break;
}
-
- case 0x79: {
- // STRH/LDRH(immediate)
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- imm *= 2;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
-
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_16) {
- st2((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
- rdid = -1;
-
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_16) {
- rval = ld2s((int)rval);
- } else trap = (2+1);
- rdid = -1;
- break;
- }
- default: trap = (2+1);
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OP_LOAD_R_16) {
+ rval = ld1s((int)regs[rn] + (int)regs[rm]);
+ } else {
+ trap = (2+1);
}
break;
}
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x79: {
+ // STRH/LDRH(immediate)
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ imm *= 2;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_16) {
+ st2((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+ rdid = -1;
- case 0x5c: {
- // ldr
- is_f = true;
- // address = delta
- int address = ir << 8 >> 13;
- address *= 4;
- if(address >= _buf.length-3) trap = (5 + 1);
- frval = ld8f(pc + address);
break;
}
- case 0xB9: {
- // str/ldr(immediate) 32 bits
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
- imm *= 4;
-
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
-
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_32) {
- st4((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_32) {
- rval = ld4s((int) rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_16) {
+ rval = ld2s((int)rval);
+ } else trap = (2+1);
+ rdid = -1;
break;
}
- case 0xF9: {
- // str/ldr(immediate) 64 bits
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 8;
-
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OP_STORE_IMM_64) {
- st8((int)rval, regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OP_LOAD_IMM_64) {
- rval = ld8((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
- break;
+ default: trap = (2+1);
}
- case 0xf8: {
- // LDR/STR (register + index) 64 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OP_STORE_R_64) {
- st8((int)regs[rn] + (int)regs[rm], regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OP_LOAD_R_64) {
- rval = ld8((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
+ break;
+ }
- break;
- }
+ case 0x8A: { // AND
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rn] & regs[rm];
+ break;
+ }
- case 0xB8: {
- // LDR/STR (register + index) 32 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OP_STORE_R_32) {
- st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if( opcode1 == arm.OP_LOAD_R_32) {
- rval = ld4s((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
+ case 0x8B: {
+ // add(shifted register)
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ long lhs = regs[rn];
+ long rhs = regs[rm];
+ rval = lhs + rhs;
+ break;
+ }
- break;
- }
+ case 0x90: { // adrp
+ int immhi = ( (ir& ~0x1F) << 8 ) >> 8;
+ int immlo = (ir>>29)& 3;
+ int imm = ((immhi<<2) | immlo) << 12;
+ rval = (pc & ~0xFFF) + imm;
+ break;
+ }
- case 0xFC: {
- // LDR/STR (register + index) float 64 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- is_f = true;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OPF_STORE_R_64) {
- st8((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OPF_LOAD_R_64) {
- frval = ld8f((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
- }
+ case 0x91: { // add(immediate)
+ int rn = (ir >> 5) & 0x1F;
+ int immediate = ir << 10 >> 20;
+ // only hit it twice
+ rval = regs[rn] + immediate;
+ break;
+ }
+ case 0x92: { // and(immediate)
+ int imm12 = (ir >> 10) & 0x1FFF;
+ long immediate = arm.decodeImm12(imm12);
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] & immediate;
+ break;
+ }
+ case 0x93: {
+ // asr(immediate)
+ int imm = (ir >> 16) & 0x3F;
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] >> (imm);
+ break;
+ }
- break;
+ case 0x94, 0x95, 0x96, 0x97: { // bl
+ rval = pc + 4;
+ regs[arm.X30] = rval;
+ int imm26 = (ir & 0x03FFFFFF);
+ int imm = (imm26 << 6) >> 6;
+ pc = pc + (imm << 2) ;
+ if( pc == Encoding.SENTINEL_CALLOC ) {
+ assert (_heap&7) == 0; // 8-byte aligned
+ long size = regs[arm.X0]*regs[arm.X1];
+ size = (size+7) & -8; // 8-byte aligned
+ regs[arm.X0] = _heap;
+ _heap += (int)size;
+ pc = (int)rval;
+ rdid = -1;
}
+ if( pc == Encoding.SENTINEL_WRITE ) {
+ ByteArrayOutputStream baos = switch((int)regs[0]) {
+ case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout;
+ case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr;
+ default -> throw new IllegalArgumentException();
+ };
+ baos.write(_buf,(int)regs[1],(int)regs[2]);
+ regs[0] = regs[2];
+ pc = (int)rval;
+ rdid = -1;
+ }
+ pc -= 4;
+ break;
+ }
- case 0xBC: {
- // LDR/STR (register + index) float 32 bits
- int opc = ir >> 21 & 0x7;
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- is_f = true;
- // full opcode
- opcode1 = (ir >> 21) & 0x7FF;
- switch(opc) {
- case 0x1: {
- if(opcode1 == arm.OPF_STORE_R_32) {
- st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
- }else {
- trap = (2+1);
- }
- // store(expected to store the length here)
-
- rdid = -1;
- break;
- }
- case 0x3: {
- // load
- if(opcode1 == arm.OPF_LOAD_R_32) {
- frval = ld4f((int) (regs[rn] + regs[rm]));
- } else {
- trap = (2+1);
- }
- break;
- }
- default: trap = (2+1);
+ case 0x9A: {
+ // conditional select(csel)
+ int rm = (ir >> 16) & 0x1F;
+ switch((ir >> 12) & 0xF) {
+ case 0x0: if(Z) rval = regs[rm]; break; // eq
+ case 0x1: if(!Z) rval = regs[rm]; break; // ne
+ case 0x2: if(C) rval = regs[rm]; break; // cs
+ case 0x3: if(!C) rval = regs[rm]; break;
+ case 0x4: if(N) rval = regs[rm]; break; // mi
+ case 0x5: if(!N) rval = regs[rm]; break; // pl
+ case 0x6: if(V) rval = regs[rm]; break; // vs
+ case 0x7: if(!V) rval = regs[rm]; break; // vc
+ case 0x8: if(C && !Z) rval = regs[rm]; break; // hi
+ case 0x9: if(!C || Z) rval = regs[rm]; break; // ls
+ case 0xA: if(N == V) rval = regs[rm]; break; // ge
+ case 0xB: if(N != V) rval = regs[rm]; break; // lt
+ case 0xC: if(!Z && N == V) rval = regs[rm]; break; // gt
+ case 0xD: if(Z || N != V) rval = regs[rm]; break; // le
+ case 0xE: rval = regs[rm]; break; // always executed(al)
+ default: rval = regs[(ir >> 5) & 0x1F];
+ }
+ break;
+ }
+ case 0x9B: { // mul
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rn] * regs[rm];
+ break;
+ }
+ case 0x9E: {
+ // scvtf
+ is_f = true;
+ int rs1 = (ir >> 5) & 0x1F;
+ frval = (double)regs[rs1];
+ break;
+ }
+
+ case 0xAA: {
+ // MOV(register)
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rm];
+ break;
+ }
+
+ case 0xB8: {
+ // LDR/STR (register + index) 32 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OP_STORE_R_32) {
+ st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
}
+ // store(expected to store the length here)
+ rdid = -1;
break;
}
-
- case 0xBD: {
- // LDR/STR(immediate) 32 bits floats
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 4;
- is_f = true;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OPF_STORE_IMM_32) {
- st4((int)rval, (int)regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OPF_LOAD_IMM_32) {
- frval = ld4s((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
+ case 0x3: {
+ // load
+ if( opcode1 == arm.OP_LOAD_R_32) {
+ rval = ld4s((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
}
break;
}
- case 0xFD: {
- // LDR/STR(immediate) 64 bits floats
- int base = ir >> 5 & 0x1F;
- int imm = (ir >> 10) & 0xFFF;
-
- imm *= 4;
- is_f = true;
- rval = regs[base] + imm;
- int opc = (ir >> 22) & 0x3;
- // full opcode
- opcode1 = (ir >> 22) & 0x3FF;
- switch(opc) {
- case 0x0: {
- // store
- if(opcode1 == arm.OPF_STORE_IMM_64) {
- st8((int)rval, regs[rdid]);
- } else trap = (2+1);
-
- rdid = -1;
- break;
- }
- case 0x1: {
- // LDR (immediate)
- if(opcode1 == arm.OPF_LOAD_IMM_64) {
- frval = ld8((int)rval);
- } else trap = (2+1);
- break;
- }
- default: trap = (2+1);
- }
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+
+ case 0xB9: {
+ // str/ldr(immediate) 32 bits
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ imm *= 4;
+
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_32) {
+ st4((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
break;
}
- case 0x9b: {
- // mul
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rn] * regs[rm];
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_32) {
+ rval = ld4s((int) rval);
+ } else trap = (2+1);
break;
}
- case 0x54: {
- // b.cond
- int imm19 = ir << 8 >> 13;
- imm19 = pc + (imm19 * 4) - 4;
- rdid = -1;
+ default: trap = (2+1);
+ }
+ break;
+ }
- switch(ir & 0xF) {
- case 0x0: if(Z) pc = imm19; break; // eq
- case 0x1: if(!Z) pc = imm19; break; // ne
- case 0x2: if(C) pc = imm19; break; // cs
- case 0x3: if(!C) pc = imm19; break;
- case 0x4: if(N) pc = imm19; break; // mi
- case 0x5: if(!N) pc = imm19; break; // pl
- case 0x6: if(V) pc = imm19; break; // vs
- case 0x7: if(!V) pc = imm19; break; // vc
- case 0x8: if(C && !Z) pc = imm19; break; // hi
- case 0x9: if(!C || Z) pc = imm19; break; // ls
- case 0xA: if(N == V) pc = imm19; break; // ge
- case 0xB: if(N != V) pc = imm19; break; // lt
- case 0xC: if(!Z && N == V) pc = imm19; break; // gt
- case 0xD: if(Z || N != V) pc = imm19; break; // le
- case 0xE: pc = imm19; break; // always executed(al)
- default: trap = (2+1);
+ case 0xBC: {
+ // LDR/STR (register + index) float 32 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ is_f = true;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OPF_STORE_R_32) {
+ st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
}
+ // store(expected to store the length here)
+
+ rdid = -1;
break;
}
- case 0x9a: {
- // conditional select(csel)
- int rm = (ir >> 16) & 0x1F;
- switch((ir >> 12) & 0xF) {
- case 0x0: if(Z) rval = regs[rm]; break; // eq
- case 0x1: if(!Z) rval = regs[rm]; break; // ne
- case 0x2: if(C) rval = regs[rm]; break; // cs
- case 0x3: if(!C) rval = regs[rm]; break;
- case 0x4: if(N) rval = regs[rm]; break; // mi
- case 0x5: if(!N) rval = regs[rm]; break; // pl
- case 0x6: if(V) rval = regs[rm]; break; // vs
- case 0x7: if(!V) rval = regs[rm]; break; // vc
- case 0x8: if(C && !Z) rval = regs[rm]; break; // hi
- case 0x9: if(!C || Z) rval = regs[rm]; break; // ls
- case 0xA: if(N == V) rval = regs[rm]; break; // ge
- case 0xB: if(N != V) rval = regs[rm]; break; // lt
- case 0xC: if(!Z && N == V) rval = regs[rm]; break; // gt
- case 0xD: if(Z || N != V) rval = regs[rm]; break; // le
- case 0xE: rval = regs[rm]; break; // always executed(al)
- default: {
- rval = regs[(ir >> 5) & 0x1F];
- }
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OPF_LOAD_R_32) {
+ frval = ld4f((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
}
break;
}
- case 0xeb: {
- // subs(shifted register)
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- long lhs = regs[rn];
- long rhs = regs[rm];
- rval = lhs - rhs;
-
- // set flags as a side effect
- Z = (rval == 0);
- N = (rval < 0);
- C = lhs >= rhs;
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+
+ case 0xBD: {
+ // LDR/STR(immediate) 32 bits floats
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 4;
+ is_f = true;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OPF_STORE_IMM_32) {
+ st4((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
- boolean sign_lhs = (lhs >>> 63) != 0;
- boolean sign_rhs = (rhs >>> 63) != 0;
- boolean sign_res = (rval >>> 63) != 0;
- V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
rdid = -1;
break;
}
- case 0xF1: {
- // subs(immediate)
- int rn = (ir >> 5) & 0x1F;
- int immediate = ir << 10 >> 20;
- long lhs = regs[rn];
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OPF_LOAD_IMM_32) {
+ frval = ld4s((int)rval);
+ } else trap = (2+1);
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+
+ case 0xD2: {
+ // movz
+ // get immediate
+ rval = (ir >> 5) & 0x7FFF;
+ break;
+ }
+
+ case 0xEB: {
+ // subs(shifted register)
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ long lhs = regs[rn];
+ long rhs = regs[rm];
+ rval = lhs - rhs;
+
+ // set flags as a side effect
+ Z = (rval == 0);
+ N = (rval < 0);
+ C = lhs >= rhs;
+
+ boolean sign_lhs = (lhs >>> 63) != 0;
+ boolean sign_rhs = (rhs >>> 63) != 0;
+ boolean sign_res = (rval >>> 63) != 0;
+ V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
+ rdid = -1;
+ break;
+ }
+
+ case 0xD3: {
+ // lsl(immediate)
+ int imm = (ir >> 16) & 0x3F;
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] << (64 - imm);
+ break;
+ }
+ case 0xD6: {
+ rdid = -1;
+ // Return to zero breaks simulation
+ if(regs[30] == 0)
+ break outer;
+ throw Utils.TODO();
+ }
- rval = lhs - immediate;
+ case 0xF1: {
+ // subs(immediate)
+ int rn = (ir >> 5) & 0x1F;
+ int immediate = ir << 10 >> 20;
+ long lhs = regs[rn];
- // set flags as a side effect
- Z = (rval == 0);
- N = (rval < 0);
- C = lhs >= immediate;
+ rval = lhs - immediate;
+
+ // set flags as a side effect
+ Z = (rval == 0);
+ N = (rval < 0);
+ C = lhs >= immediate;
+
+ boolean sign_lhs = (lhs >>> 63) != 0;
+ boolean sign_rhs = (immediate >>> 63) != 0;
+ boolean sign_res = (rval >>> 63) != 0;
+ V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
+ rdid = -1;
+ break;
+ }
+ case 0xF8: {
+ // LDR/STR (register + index) 64 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OP_STORE_R_64) {
+ st8((int)regs[rn] + (int)regs[rm], regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ // store(expected to store the length here)
- boolean sign_lhs = (lhs >>> 63) != 0;
- boolean sign_rhs = (immediate >>> 63) != 0;
- boolean sign_res = (rval >>> 63) != 0;
- V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs);
rdid = -1;
break;
}
- case 0x8B: {
- // add(shifted register)
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- long lhs = regs[rn];
- long rhs = regs[rm];
- rval = lhs + rhs;
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OP_LOAD_R_64) {
+ rval = ld8((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
+ }
break;
}
- case 0x91: {
- // add(immediate)
- int rn = (ir >> 5) & 0x1F;
- int immediate = ir << 10 >> 20;
- // only hit it twice
- rval = regs[rn] + immediate;
- break;
+ default: trap = (2+1);
}
- case 0xD3: {
- // lsl(immediate)
- int imm = (ir >> 16) & 0x3F;
- int rn = (ir >> 5) & 0x1F;
- rval = regs[rn] << (64 - imm);
+
+ break;
+ }
+ case 0xF9: {
+ // str/ldr(immediate) 64 bits
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 8;
+
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_64) {
+ st8((int)rval, regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
break;
}
- case 0x93: {
- // asr(immediate)
- int imm = (ir >> 16) & 0x3F;
- int rn = (ir >> 5) & 0x1F;
- rval = regs[rn] >> (imm);
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_64) {
+ rval = ld8((int)rval);
+ } else trap = (2+1);
break;
}
- case 0x92: {
- // and(immediate)
- int imm12 = (ir >> 10) & 0x1FFF;
- long immediate = arm.decodeImm12(imm12);
- int rn = (ir >> 5) & 0x1F;
- rval = regs[rn] & immediate;
- break;
+ default: trap = (2+1);
}
- case 0xAA: {
- // MOV(register)
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rm];
+ break;
+ }
+
+ case 0xFC: {
+ // LDR/STR (register + index) float 64 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ is_f = true;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OPF_STORE_R_64) {
+ st8((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ // store(expected to store the length here)
+
+ rdid = -1;
break;
}
- case 0xD6: {
- rdid = -1;
- if(ld4s(pc + 4) == 0) {
- break outer;
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OPF_LOAD_R_64) {
+ frval = ld8f((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
}
- }
- // bitwise
- case 0x8A: {
- // AND
- int rn = (ir >> 5) & 0x1F;
- int rm = (ir >> 16) & 0x1F;
- rval = regs[rn] & regs[rm];
break;
}
- // floats
- case 0x1E: {
- is_f = true;
- int rs1 = (ir >> 5) & 0x1F;
- int rs2 = (ir >> 16) & 0x1F;
-
- int op = (ir >> 10) & 0x3F;
- switch(op) {
- case 16: frval = fregs[rs1]; break; // fmov
- case 10:frval = fregs[rs1] + fregs[rs2]; break; // fadd
-
- case 6: if (fregs[rs2] == 0) frval = 0; else frval = fregs[rs1] / fregs[rs2]; break; // fdiv
- case 8: {
- // fcmp
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
-
- Z = (lhs == rhs);
- N = (lhs < rhs);
- C = lhs >= rhs;
- V = Double.isNaN(lhs) || Double.isNaN(rhs);
- rdid = -1;
-
- break;
- }
- case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul
- case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub
- default: trap = (2+1);
- }
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+ case 0xFD: {
+ // LDR/STR(immediate) 64 bits floats
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 4;
+ is_f = true;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OPF_STORE_IMM_64) {
+ st8((int)rval, regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
break;
}
- case 0x9e: {
- // scvtf
- is_f = true;
- int rs1 = (ir >> 5) & 0x1F;
- frval = (double)regs[rs1];
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OPF_LOAD_IMM_64) {
+ frval = ld8((int)rval);
+ } else trap = (2+1);
break;
}
default: trap = (2+1);
+ }
+ break;
}
+
+ default: trap = (2+1);
+ }
+
if(trap != 0) {
_pc = pc;
break;
diff --git a/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/src/test/java/com/seaofnodes/simple/EvalRisc5.java
index fd953342..0a1c034f 100644
--- a/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ b/src/test/java/com/seaofnodes/simple/EvalRisc5.java
@@ -10,10 +10,10 @@
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
-
+import java.io.ByteArrayOutputStream;
import java.util.Arrays;
- public class EvalRisc5 {
+public class EvalRisc5 {
// Memory image, always 0-based
public final byte[] _buf;
@@ -28,6 +28,9 @@ import java.util.Arrays;
// Start of free memory for allocation
int _heap;
+ // Standard out and err streams
+ ByteArrayOutputStream _stdout, _stderr;
+
// Cycle counters
int _cycle;
@@ -100,6 +103,17 @@ import java.util.Arrays;
if( (reladdy & 0x00100000)!=0 ) reladdy |= 0xffe00000; // Sign extension.
rval = pc + 4;
pc = pc + reladdy - 4;
+ if( pc+4 == Encoding.SENTINEL_WRITE ) {
+ ByteArrayOutputStream baos = switch((int)regs[10]) {
+ case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout;
+ case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr;
+ default -> throw new IllegalArgumentException();
+ };
+ baos.write(_buf,(int)regs[11],(int)regs[12]);
+ regs[10] = regs[12];
+ rdid = 0;
+ pc = (int)(rval - 4); // Unwind PC, as-if returned from write
+ }
break;
}
case 0x67: { // JALR (0b1100111)
@@ -112,11 +126,11 @@ import java.util.Arrays;
break outer;
}
// Inline CALLOC effect
- if( pc == Encoding.SENTINAL_CALLOC ) {
+ if( pc == Encoding.SENTINEL_CALLOC ) {
+ assert (_heap&7) == 0; // 8-byte aligned
int size = (int)(regs[10]*regs[11]);
+ size = (size+7) & -8; // 8-byte aligned
regs[10] = _heap; // Return next free address
- // Pre-zeroed; epsilon (null) collector, never recycles memory so always zero
- // Arrays.fill(_buf,_heap,_heap+size, (byte) 0 );
_heap += size;
pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc
} else
@@ -233,11 +247,11 @@ import java.util.Arrays;
} else {
rval = switch( (ir >> 12) & 7 ) { // These could be either op-immediate or op commands. Be careful.
case 0 -> (is_reg && (ir & 0x40000000) != 0) ? (rs1 - rs2) : (rs1 + rs2);
- case 1 -> rs1 << (rs2 & 0x1F);
+ case 1 -> rs1 << (rs2 & 0x3F);
case 2 -> (rs1 < rs2) ? 1 : 0;
case 3 -> (rs1 < rs2) ? 1 : 0;
case 4 -> rs1 ^ rs2;
- case 5 -> (ir & 0x40000000) != 0 ? (((int) rs1) >> (rs2 & 0x1F)) : (rs1 >> (rs2 & 0x1F));
+ case 5 -> (ir & 0x40000000) != 0 ? (rs1 >>> (rs2 & 0x3F)) : (rs1 >> (rs2 & 0x3F));
case 6 -> rs1 | rs2;
case 7 -> rs1 & rs2;
default -> rval;
diff --git a/src/test/java/com/seaofnodes/simple/Simple.java b/src/test/java/com/seaofnodes/simple/Simple.java
index 9b1e2827..1465aa6d 100644
--- a/src/test/java/com/seaofnodes/simple/Simple.java
+++ b/src/test/java/com/seaofnodes/simple/Simple.java
@@ -17,7 +17,7 @@ public class Simple {
static final int DUMP_AFTER_OPTO = 1<<1;
static final int DUMP_AFTER_TYPE_CHECK = 1<<2;
static final int DUMP_AFTER_LOOP_TREE = 1<<3;
- static final int DUMP_AFTER_INSTR_SELECT = 1<<4;
+ static final int DUMP_AFTER_SELECT = 1<<4;
static final int DUMP_AFTER_GCM = 1<<5;
static final int DUMP_AFTER_LOCAL_SCHED = 1<<6;
static final int DUMP_AFTER_REG_ALLOC = 1<<7;
@@ -32,33 +32,30 @@ public class Simple {
static final int DUMP_DISASSEMBLE = 1<<31;
- static String system_cpu = null;
- static String system_abi = null;
-
static void usage() {
System.out.println(
"""
-simple <input-file> [options] [--eval|--run ...]
+simple [options] <input-file> ...args...
Options:
- --dump - dump final intermediate representation
- --dump-after-parse - dump intermediate representation after parse
- --dump-after-opto - dump intermediate representation after opto pass
- --dump-after-type-check - dump intermediate representation after type check pass
- --dump-after-instr-select - dump intermediate representation after instrution selection pass
- --dump-after-gcm - dump intermediate representation after GCM pass
- --dump-after-local-sched - dump intermediate representation after local scheduling pass
- --dump-after-reg-alloc - dump intermediate representation after register allocation pass
- --dump-after-encode - dump intermediate representation after encoding pass
- --dump-after-all - dump intermediate representation after all passes
- --dot - dump grapical representation of intermediate code into *.dot file(s)
- -S - dump generated assembler code
- --eval ... - evaluate the compiled code in emulator
- --run ... - run the compiled code natively
- --dump-size - print the size of generated code
- --dump-time - print compilation and execution times
- --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm)
- --abi <abi-name> - use speific ABI variant (SystemV)
- --target - print native CPU and ABI
+ --dump - dump final intermediate representation
+ --dump-after-parse - dump intermediate representation after parse
+ --dump-after-opto - dump intermediate representation after opto pass
+ --dump-after-type-check - dump intermediate representation after type check pass
+ --dump-after-select - dump intermediate representation after instrution selection pass
+ --dump-after-gcm - dump intermediate representation after GCM pass
+ --dump-after-local-sched - dump intermediate representation after local scheduling pass
+ --dump-after-reg-alloc - dump intermediate representation after register allocation pass
+ --dump-after-encode - dump intermediate representation after encoding pass
+ --dump-after-all - dump intermediate representation after all passes
+ --dot - dump grapical representation of intermediate code into *.dot file(s)
+ -S - dump generated assembler code
+ --eval - evaluate the compiled code in emulator
+ --run - run the compiled code natively; this is the default
+ --dump-size - print the size of generated code
+ --dump-time - print compilation and execution times
+ --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm)
+ --abi <abi-name> - use speific ABI variant (SystemV)
+ --target - print native CPU and ABI
--version
--help
"""
@@ -66,46 +63,40 @@ Options:
System.exit(0);
}
- static void bad_usage() {
- System.err.println("ERROR: Invalid usage (use --help)");
+ static void bad_usage() { bad("Invalid usage (use --help)"); }
+ static RuntimeException bad(String err) {
+ System.err.println("ERROR: "+err);
System.exit(1);
+ return new RuntimeException(err);
}
static void target() {
- if (system_cpu == null || system_abi == null) {
- System.err.println("ERROR: Unknown target");
- System.exit(1);
- }
- System.out.print(system_cpu);
+ System.out.print(TestC.CPU_PORT);
System.out.print("-");
- System.out.println(system_abi);
- System.exit(0);
+ System.out.println(TestC.CALL_CONVENTION);
}
static void dump(CodeGen code, int dump, int pass) {
if ((dump & pass) != 0) {
if ((dump & DUMP_DOT) != 0) {
String fn = switch (pass) {
- case DUMP_AFTER_PARSE -> "01-parse.dot";
- case DUMP_AFTER_OPTO -> "02-opto.dot";
- case DUMP_AFTER_TYPE_CHECK -> "03-type_check.dot";
- case DUMP_AFTER_LOOP_TREE -> "04-loop_tree.dot";
- case DUMP_AFTER_INSTR_SELECT -> "05-instr_select.dot";
- case DUMP_AFTER_GCM -> "06-gcm.dot";
- case DUMP_AFTER_LOCAL_SCHED -> "07-local_sched.dot";
- case DUMP_AFTER_REG_ALLOC -> "08-reg_allos.dot";
- case DUMP_AFTER_ENCODE -> "09-local_sched.dot";
- case DUMP_FINAL -> "10-final.dot";
- default -> throw Utils.TODO();
+ case DUMP_AFTER_PARSE -> "01-parse.dot";
+ case DUMP_AFTER_OPTO -> "02-opto.dot";
+ case DUMP_AFTER_TYPE_CHECK -> "03-type_check.dot";
+ case DUMP_AFTER_LOOP_TREE -> "04-loop_tree.dot";
+ case DUMP_AFTER_SELECT -> "05-instr_select.dot";
+ case DUMP_AFTER_GCM -> "06-gcm.dot";
+ case DUMP_AFTER_LOCAL_SCHED -> "07-local_sched.dot";
+ case DUMP_AFTER_REG_ALLOC -> "08-reg_allos.dot";
+ case DUMP_AFTER_ENCODE -> "09-local_sched.dot";
+ case DUMP_FINAL -> "10-final.dot";
+ default -> throw Utils.TODO();
};
try {
Files.writeString(Path.of(fn),
- new GraphVisualizer().generateDotOutput(code._stop, null, null));
- } catch(IOException e) {
- System.err.println("ERROR: Cannot write DOT file");
- System.exit(1);
- }
+ new GraphVisualizer().generateDotOutput(code._stop, null, null));
+ } catch(IOException e) { throw bad("Cannot write DOT file"); }
} else {
if ((dump & DUMP_PASS_NAME) != 0) {
System.err.println(switch (pass) {
@@ -113,11 +104,11 @@ Options:
case DUMP_AFTER_OPTO -> "After OPTO:";
case DUMP_AFTER_TYPE_CHECK -> "After Type Check:";
case DUMP_AFTER_LOOP_TREE -> "After Loop Tree:";
- case DUMP_AFTER_INSTR_SELECT -> "After Instruction Selection:";
+ case DUMP_AFTER_SELECT -> "After Code Selection:";
case DUMP_AFTER_GCM -> "After GCM:";
case DUMP_AFTER_LOCAL_SCHED -> "After Local Scheduling:";
case DUMP_AFTER_REG_ALLOC -> "After Register Allocation:";
- case DUMP_AFTER_ENCODE -> "After Instruction Encoding:";
+ case DUMP_AFTER_ENCODE -> "After Encoding:";
case DUMP_FINAL -> "Final:";
default -> throw Utils.TODO();
});
@@ -132,24 +123,24 @@ Options:
double t, total = 0;
total += t = code._tParse / 1e3;
- System.out.println(String.format("Parsing Time: %.3f sec", t));
+ System.out.printf( "Parsing Time: %.3f sec%n", t);
total += t = code._tOpto / 1e3;
- System.out.println(String.format("Optimization Time: %.3f sec", t));
+ System.out.printf( "Optimization Time: %.3f sec%n", t);
total += t = code._tTypeCheck / 1e3;
- System.out.println(String.format("Type Checking Time: %.3f sec", t));
+ System.out.printf( "Type Checking Time: %.3f sec%n", t);
total += t = code._tLoopTree / 1e3;
- System.out.println(String.format("Loop Tree Time: %.3f sec", t));
+ System.out.printf( "Loop Tree Time: %.3f sec%n", t);
total += t = code._tInsSel / 1e3;
- System.out.println(String.format("Instruction Selection Time: %.3f sec", t));
+ System.out.printf( "Code Selection Time: %.3f sec%n", t);
total += t = code._tGCM / 1e3;
- System.out.println(String.format("GCM Time: %.3f sec", t));
+ System.out.printf( "GCM Time: %.3f sec%n", t);
total += t = code._tLocal / 1e3;
- System.out.println(String.format("Local Scheduling Time: %.3f sec", t));
+ System.out.printf( "Local Scheduling Time: %.3f sec%n", t);
total += t = code._tRegAlloc / 1e3;
- System.out.println(String.format("Register Allocation Time: %.3f sec", t));
+ System.out.printf( "Register Allocation Time: %.3f sec%n", t);
total += t = code._tEncode / 1e3;
- System.out.println(String.format("Instruction Encoding Time: %.3f sec", t));
- System.out.println(String.format("TOTAL COMPILATION TIME: %.3f sec", total));
+ System.out.printf( "Encoding Time: %.3f sec%n", t);
+ System.out.printf( "TOTAL COMPILATION TIME: %.3f sec%n", total);
}
static String getInput() {
@@ -159,9 +150,8 @@ Options:
public static void main(String[] args) throws Exception {
String input_filename = null;
- boolean use_stdin = false;
boolean do_eval = false;
- boolean do_run = false;
+ boolean do_run = true;
boolean do_codegen = false;
boolean do_print_size = false;
boolean do_print_time = false;
@@ -171,78 +161,62 @@ Options:
String cpu = null;
String abi = null;
- // TODO: autodetect
- system_cpu = "x86_64_v2";
- system_abi = "SystemV";
-
// Parse command line
-loop: for (int i = 0; i < args.length; i++) {
+ int i; for( i = 0; i < args.length; i++ ) {
String arg = args[i];
- if (arg.charAt(0) == '-') {
- switch (arg) {
- case "-": use_stdin = true; break;
- case "--dump": dump |= DUMP_FINAL; break;
- case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break;
- case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break;
- case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break;
- case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break;
- case "--dump-after-instr-select": dump |= DUMP_AFTER_INSTR_SELECT; break;
- case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break;
- case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break;
- case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break;
- case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break;
- case "--dump-after-all": dump |= DUMP_AFTER_ALL; break;
- case "--dot": dump |= DUMP_DOT; break;
- case "-S": dump |= DUMP_DISASSEMBLE; break;
- case "--eval": do_eval = true; first_arg = i + 1; break loop;
- case "--run": do_run = true; first_arg = i + 1; break loop;
- case "--dump-size": do_print_size = true; break;
- case "--dump-time": do_print_time = true; break;
- case "--cpu": if (cpu != null
- || i + 1 >= args.length
- || args[i + 1].charAt(0) == '-') bad_usage();
- cpu = args[i + 1];
- i++;
- break;
- case "--abi": if (abi != null
- || i + 1 >= args.length
- || args[i + 1].charAt(0) == '-') bad_usage();
- abi = args[i + 1];
- i++;
- break;
- case "--target": target();
- case "--version": throw Utils.TODO();
- case "--help": usage();
- default: bad_usage();
- }
- } else {
- if (input_filename != null || use_stdin) bad_usage();
+ if( arg.charAt(0) != '-' ) {
input_filename = arg;
+ break;
}
- }
- if (input_filename == null && !use_stdin) {
- System.err.println("ERROR: no input file' (use --help)");
- System.exit(1);
+ switch (arg) {
+ case "-": input_filename=""; break;
+ case "--dump": dump |= DUMP_FINAL; break;
+ case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break;
+ case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break;
+ case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break;
+ case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break;
+ case "--dump-after-select": dump |= DUMP_AFTER_SELECT; break;
+ case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break;
+ case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break;
+ case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break;
+ case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break;
+ case "--dump-after-all": dump |= DUMP_AFTER_ALL; break;
+ case "--dot": dump |= DUMP_DOT; break;
+ case "-S": dump |= DUMP_DISASSEMBLE; break;
+ case "--eval": do_eval = true ; do_run = false; break;
+ case "--run": do_run = true ; break;
+ case "--norun": do_run = false; break;
+ case "--dump-size": do_print_size = true; break;
+ case "--dump-time": do_print_time = true; break;
+ case "--cpu": if (cpu != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage();
+ cpu = args[++i];
+ break;
+ case "--abi": if (abi != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage();
+ abi = args[++i];
+ break;
+ case "--target": target(); break;
+ case "--version": throw Utils.TODO();
+ case "--help": usage();
+ default: bad_usage();
+ }
}
+ if (input_filename == null) throw bad("no input file' (use --help)");
+ if( !input_filename.isEmpty() && !input_filename.endsWith(".smp") )
+ throw bad("File extension must be .smp");
+ String base = input_filename.substring(0,input_filename.length()-4);
+
if (do_run || (dump & DUMP_DISASSEMBLE) != 0 || do_print_size) {
- if (cpu == null) cpu = system_cpu;
- if (abi == null) abi = system_abi;
- if (cpu == null || abi == null) {
- System.err.println("ERROR: Cannot compile for unknown target");
- System.exit(1);
- }
+ if (cpu == null) cpu = TestC.CPU_PORT;
+ if (abi == null) abi = TestC.CALL_CONVENTION;
do_codegen = true;
}
// Read input file
try {
- src = use_stdin ? getInput() : Files.readString(Path.of(input_filename));
- } catch(IOException e) {
- System.err.println("ERROR: Cannot read input file");
- System.exit(1);
- }
+ src = input_filename.isEmpty() ? getInput() : Files.readString(Path.of(input_filename));
+ } catch( IOException e ) { throw bad("Cannot read input file: "+input_filename); }
// Compilation pipeline
CodeGen code = new CodeGen(src);
@@ -260,8 +234,8 @@ loop: for (int i = 0; i < args.length; i++) {
dump(code, dump, DUMP_AFTER_LOOP_TREE);
if (do_codegen) {
- code.instSelect(PORTS, cpu, abi);
- dump(code, dump, DUMP_AFTER_INSTR_SELECT);
+ code.instSelect(cpu, abi, PORTS);
+ dump(code, dump, DUMP_AFTER_SELECT);
}
code.GCM();
@@ -276,6 +250,8 @@ loop: for (int i = 0; i < args.length; i++) {
code.encode();
dump(code, dump, DUMP_AFTER_ENCODE);
+
+ code.exportELF(base+".o");
}
dump(code, dump, DUMP_FINAL);
@@ -285,7 +261,7 @@ loop: for (int i = 0; i < args.length; i++) {
}
if (do_print_size) {
- System.out.println(String.format("Code Size: %d", code._encoding._bits.size()));
+ System.out.printf( "Code Size: %d%n", code._encoding._bits.size());
}
if (do_print_time) {
@@ -295,19 +271,19 @@ loop: for (int i = 0; i < args.length; i++) {
if (do_eval) {
// TODO: Support for evaluation of functions with different argument numbers and types
long t = System.currentTimeMillis();
- long arg = (first_arg < args.length) ? Integer.valueOf(args[first_arg]) : 0;
+ long arg = (i+1 < args.length) ? Integer.parseInt(args[i+1]) : 0;
System.out.println(Eval2.eval(code, arg, 100000));
if (do_print_time) {
- System.out.println(String.format("EXECUTION TIME: %.3f sec",
- (System.currentTimeMillis() - t) / 1e3));
- }
- } else if (do_run) {
- if (cpu != system_cpu || abi != system_abi) {
- System.err.println("ERROR: cannot run code on not native target");
- System.exit(1);
+ System.out.printf( "EXECUTION TIME: %.3f sec%n",
+ (System.currentTimeMillis() - t) / 1e3);
}
-
- throw Utils.TODO();
+ }
+ if (do_run) {
+ if ( !TestC.CPU_PORT.equals( cpu ) || !TestC.CALL_CONVENTION.equals( abi ) )
+ throw bad("cannot run code on not native target");
+ String exe = TestC.OS.startsWith("Windows") ? base+".exe" : base;
+ String result = com.seaofnodes.simple.TestC.gcc(base+".o", null, null, true, exe);
+ System.out.print(result);
}
}
}
diff --git a/src/test/java/com/seaofnodes/simple/TestC.java b/src/test/java/com/seaofnodes/simple/TestC.java
index 5609758b..93fa9b66 100644
--- a/src/test/java/com/seaofnodes/simple/TestC.java
+++ b/src/test/java/com/seaofnodes/simple/TestC.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.io.InputStream;
-import java.io.IOException;
+import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
// Call a C driver program, which calls a Simple-generated .o, and self-checks.
@@ -16,8 +16,8 @@ public abstract class TestC {
public static final String CALL_CONVENTION = OS.startsWith("Windows") ? "Win64" : "SystemV";
public static final String CPU_PORT = switch( CPU ) {
- case "amd64" -> "x86_64_v2";
- default -> throw Utils.TODO("Map Yer CPU Port Here");
+ case "amd64" -> "x86_64_v2";
+ default -> throw Utils.TODO("Map Yer CPU Port Here");
};
public static void run( String file, int spills ) throws IOException { run(file,"",spills); }
@@ -35,48 +35,16 @@ public abstract class TestC {
// Compile and export Simple
String src = Files.readString(Path.of(sfile));
- _run(src,CALL_CONVENTION,"",cfile,efile,"S",expected,spills);
+ run(src,CALL_CONVENTION,"",cfile,efile,"S",expected,spills);
}
- static void _run( String src, String simple_conv, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException {
+ public static void run( String src, String simple_conv, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException {
String bin = efile+xtn;
String obj = bin+".o";
+ String exe = OS.startsWith("Windows") ? bin+".exe" : bin;
// Compile simple, emit ELF
CodeGen code = new CodeGen(src).driver( CPU_PORT, simple_conv, obj);
-
- // Compile the C program
- var params = new String[] {
- //if (USE_WSL) "wsl.exe";
- "gcc",
- cfile,
- obj,
- "-lm", // Picks up 'sqrt' for newtonFloat tests to compare
- "-g",
- "-o",
- bin,
- "-D",
- "CALL_CONV="+c_conv,
- };
- Process gcc = new ProcessBuilder(params).redirectErrorStream(true).start();
- byte error;
- try { error = (byte)gcc.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); }
- String result = new String(gcc.getInputStream().readAllBytes());
- if( error!=0 ) {
- System.err.println("gcc error code: "+error);
- System.err.println(result);
- }
- assertEquals( 0, error );
- //assertTrue(result.isEmpty()); // No data in error stream
-
- // Execute results
- Process smp = new ProcessBuilder(bin).redirectErrorStream(true).start();
- try { error = (byte)smp.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); }
- result = new String(smp.getInputStream().readAllBytes());
- if( error!=0 ) {
- System.err.println("exec error code: "+error);
- System.err.println(result);
- }
- assertEquals( 0, error );
+ String result = gcc(obj, c_conv, cfile, false, exe );
assertEquals(expected,result);
// Allocation quality not degraded
@@ -84,6 +52,55 @@ public abstract class TestC {
if( delta==0 ) delta = 1;
if( spills != -1 )
assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);
+ }
+
+ public static String gcc( String obj, String c_conv, String cfile, boolean stdin, String... args ) throws IOException {
+
+ // Compile the C program. Compiling code and constants in the low
+ // 2Gig. Pointers are 64b BUT since always in the low 2G all the
+ // high bits are zero - and Simple code can be emitted treating
+ // pointers as 4bytes.
+ var params = new Ary<>(String.class);
+ params.add("gcc");
+ if( cfile!=null ) params.add(cfile); // Associated C driver, usually has a `main`
+ params.addAll(new String[] {
+ obj,
+ "-lm", // Picks up 'sqrt' for newtonFloat tests to compare
+ "-g",
+ "-o",
+ args[0],
+ });
+ // Calling convention for C calls, if any
+ if( cfile!=null ) {
+ params.add("-D");
+ params.add("CALL_CONV="+c_conv);
+ }
+ // Run GCC to link (optionally compile C driver code)
+ Process gcc = new ProcessBuilder(params.asAry()).redirectErrorStream(true).start();
+ int exit;
+ try {
+ boolean normal = gcc.waitFor(2, TimeUnit.SECONDS);
+ exit = normal ? gcc.exitValue() : -1; // no exit???
+ } catch( InterruptedException e ) {
+ throw new IOException("interrupted");
+ }
+ String result = new String(gcc.getInputStream().readAllBytes());
+ if( exit!=0 ) {
+ System.err.println("gcc error code: "+exit);
+ System.err.println(result);
+ }
+ assertEquals( 0, exit );
+ //assertTrue(result.isEmpty()); // No data in error stream
+
+ // Execute results
+ ProcessBuilder smp = new ProcessBuilder(args);
+ if( stdin ) smp.redirectInput(ProcessBuilder.Redirect.INHERIT);
+ Process p = smp.start();
+ try { exit = (byte)p.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); }
+ result = new String(p.getInputStream().readAllBytes());
+ if( exit!=0 )
+ System.err.println("exec exit code: "+exit);
+ return result;
}
}
diff --git a/src/test/java/com/seaofnodes/simple/TypeTest.java b/src/test/java/com/seaofnodes/simple/TypeTest.java
index d94f5b5a..660f984a 100644
--- a/src/test/java/com/seaofnodes/simple/TypeTest.java
+++ b/src/test/java/com/seaofnodes/simple/TypeTest.java
@@ -20,9 +20,9 @@ public class TypeTest {
TypeStruct s2 = TypeStruct.make("s2", new Field[]{
Field.make("a", TypeInteger.BOT,-3, false),
Field.make("b", TypeInteger.BOT,-4, false) });
- Assert.assertEquals(s1.makeRO(), s1.glb());
+ Assert.assertEquals(s1.makeRO(), s1.glb(false));
Assert.assertNotEquals(s1, s1.dual());
- Assert.assertEquals(s1.makeRO(), s1.dual().glb());
+ Assert.assertEquals(s1.makeRO(), s1.dual().glb(false));
TypeMem m1 = TypeMem.make(1,TypeNil.NIL);
TypeMem m2 = TypeMem.make(2,TypeInteger.U16);
@@ -38,9 +38,9 @@ public class TypeTest {
Assert.assertEquals(TypeMem.make(0,Type.BOTTOM), m1.meet(m3));
Assert.assertEquals(TypeMem .BOT, m3.meet(m4));
- Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.glb());
+ Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.glb(false));
Assert.assertEquals(TypeMem.make(1,Type.XNIL), m1.dual());
- Assert.assertEquals(m4.dual(), m4.glb().dual());
+ Assert.assertEquals(m4.dual(), m4.glb(false).dual());
TypeMemPtr ptr1 = TypeMemPtr.make(s1);
Assert.assertEquals(s1, ptr1._obj);
@@ -55,13 +55,13 @@ public class TypeTest {
Assert.assertEquals(s2, ptr2nil._obj);
Assert.assertNotEquals(ptr1, ptr2);
- Assert.assertNotEquals(ptr1, ptr1.glb());
- Assert.assertEquals(ptr1nil.makeRO(), ptr1.glb());
+ Assert.assertNotEquals(ptr1, ptr1.glb(false));
+ Assert.assertEquals(ptr1nil.makeRO(), ptr1.glb(false));
Assert.assertEquals(ptr1, ptr1.dual().dual());
- Assert.assertEquals(ptr1.glb().makeRO(), ptr1.dual().glb());
+ Assert.assertEquals(ptr1.glb(false).makeRO(), ptr1.dual().glb(false));
Assert.assertEquals(TypeMemPtr.makeNullable(TypeStruct.BOT), ptr1.meet(ptr2nil));
- Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeNil.NIL).makeRO());
+ Assert.assertEquals(ptr1.glb(false), ptr1.meet(TypeNil.NIL).makeRO());
TypeMemPtr TOP = TypeMemPtr.TOP;
TypeMemPtr BOT = TypeMemPtr.makeNullable(TypeStruct.BOT);
diff --git a/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java b/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
index f119fa1a..4f86d0be 100644
--- a/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
+++ b/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
@@ -97,7 +97,7 @@ public class ScriptGenerator {
private static final List<TypeInt> INTTYPES = new ArrayList<>();
static {
- for( var e : Parser.defaultTypes().entrySet() ) {
+ for( var e : Parser.TYPES.entrySet() ) {
if( e.getValue() instanceof TypeInteger ) {
INTTYPES.add(new TypeInt(e.getKey()));
}
diff --git a/src/test/java/com/seaofnodes/simple/progs/echo.smp b/src/test/java/com/seaofnodes/simple/progs/echo.smp
new file mode 100644
index 00000000..8eafd73b
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/echo.smp
@@ -0,0 +1,3 @@
+// -*- mode: java; -*-
+// Echo stdin to stdout.
+return sys.io.p( sys.io.stdin() );
diff --git a/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp b/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp
new file mode 100644
index 00000000..07ff935f
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp
@@ -0,0 +1,3 @@
+// -*- mode: java; -*-
+sys.io.p("Hello, World!");
+return 0;
diff --git a/src/test/java/com/seaofnodes/simple/progs/jig.smp b/src/test/java/com/seaofnodes/simple/progs/jig.smp
index 1daeee09..fd3e7b9c 100644
--- a/src/test/java/com/seaofnodes/simple/progs/jig.smp
+++ b/src/test/java/com/seaofnodes/simple/progs/jig.smp
@@ -1,2 +1,6 @@
// -*- mode: java; -*-
+// Should fold away sign extend
+struct Person { i8 age;};
+Person !p = new Person;
+p.age = (arg<<48)>>48;
return 0;
diff --git a/src/test/java/com/seaofnodes/simple/progs/person.smp b/src/test/java/com/seaofnodes/simple/progs/person.smp
index 9f0f5bea..507fb83b 100644
--- a/src/test/java/com/seaofnodes/simple/progs/person.smp
+++ b/src/test/java/com/seaofnodes/simple/progs/person.smp
@@ -1,6 +1,6 @@
// -*-java-*-
struct Person {
- int age;
+ i32 age;
};
val fcn = { Person?[] ps, int x ->
diff --git a/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp b/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp
new file mode 100644
index 00000000..67369feb
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp
@@ -0,0 +1,4 @@
+struct Person { i32 age;};
+Person !p = new Person;
+p.age += arg;
+return p.age;
diff --git a/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp b/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp
new file mode 100644
index 00000000..cfb3fbcc
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp
@@ -0,0 +1,4 @@
+struct Person {i64 age;}
+Person !p = new Person;
+p.age += arg;
+return p.age;
diff --git a/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp b/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp
new file mode 100644
index 00000000..0cf70392
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp
@@ -0,0 +1,5 @@
+// Should fold away sign extend
+struct Person { i8 age;};
+Person !p = new Person;
+p.age = (arg<<48)>>48;
+return 0; \ No newline at end of file
diff --git a/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp b/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp
new file mode 100644
index 00000000..48cc6409
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp
@@ -0,0 +1,4 @@
+struct Person { i32 age;};
+Person !p = new Person;
+p.age = (arg<<17)>>17;
+return 0; \ No newline at end of file
diff --git a/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp b/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp
new file mode 100644
index 00000000..3120429b
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp
@@ -0,0 +1,4 @@
+struct Person { i32 age;};
+Person !p = new Person;
+p.age = (arg<<48)>>48;
+return 0; \ No newline at end of file
diff --git a/src/test/java/com/seaofnodes/simple/progs/store_peep.smp b/src/test/java/com/seaofnodes/simple/progs/store_peep.smp
new file mode 100644
index 00000000..c3feddd5
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/progs/store_peep.smp
@@ -0,0 +1,3 @@
+i64 a = 123456789012345;
+i32 b = a; // truncate high order bits
+return b; \ No newline at end of file