summaryrefslogtreecommitdiff
path: root/chapter25/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/test')
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java88
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/EvalRisc5.java2
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data.c22
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data_import.c14
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/spill/README.md10
5 files changed, 130 insertions, 6 deletions
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
index 41225097..bde25ab7 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
@@ -21,6 +21,87 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class Chapter25Test {
+ @Test
+ public void testExternData() throws IOException {
+ String src = """
+ i32 counter="C";
+ i8 small="C";
+ f64 fraction="C";
+ {int} bump="C";
+ val test_global={ ->
+ val before=counter;
+ counter=before;
+ counter=++counter+1;
+ counter+=1;
+ val mid=bump();
+ small++;
+ fraction=fraction+0.5;
+ return before*10000+mid*100+counter;
+ };
+ """;
+ TestC.runC(src,"extern_data","",-1);
+ }
+
+ @Test
+ public void testExternDataEncoding() {
+ for( String cpu : new String[]{"arm","riscv"} ) {
+ CodeGen code = new CheckedCodeGen("i32 counter=\"C\"; counter=counter+3; return counter;");
+ // Exercise signed low-12 relocation arithmetic, past the first page.
+ int addr = 0x3800;
+ code._externDataAddresses.put("counter",addr);
+ code.driver(cpu,"SystemV",true,false);
+ byte[] image = new byte[1<<20];
+ var bits = code._encoding._bits;
+ System.arraycopy(bits.buf(),0,image,0,bits.size());
+ if( cpu.equals("arm") ) {
+ EvalArm64 arm = new EvalArm64(image,1<<16);
+ arm.st4(addr,-7);
+ assertEquals(0,arm.step(1000));
+ assertEquals(-4,arm.regs[0]);
+ assertEquals(-4,arm.ld4s(addr));
+ } else {
+ EvalRisc5 r5 = new EvalRisc5(image,1<<16);
+ r5.st4(addr,-7);
+ assertEquals(0,r5.step(1000));
+ assertEquals(-4,r5.regs[10]);
+ assertEquals(-4,r5.ld4s(addr));
+ }
+ }
+ }
+
+ @Test
+ public void testExternDataImports() throws IOException {
+ Path dir = Files.createTempDirectory(Path.of("build/objs"),"extern_data_");
+ String globals = "i32 counter=\"C\"; val read={ -> counter; };";
+ CodeGen globalCode = new CodeGen(null,dir.toString(),null,"Globals",globals,126,true,TypeInteger.BOT)
+ .driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false);
+ var clz = globalCode.compunit()._clz;
+ int counter = clz.find("counter");
+ assertTrue(clz._fields[counter]._extern);
+ assertEquals(-1,clz.offset(counter));
+ assertEquals(clz.remove(counter).size(),clz.size());
+ // Load the serialized declaration and ideal graph from Globals.o.
+ String src = """
+ i32 counter="C";
+ val test_global={ ->
+ val before=Globals.counter;
+ Globals.counter=before+1;
+ counter+=2;
+ return before*100+Globals.read();
+ };
+ """;
+ Ary<String> paths = new Ary<>(new String[]{dir.toString()});
+ for( boolean imported : new boolean[]{true,false} ) {
+ Path root = dir.resolve(imported ? "binary" : "source");
+ Files.createDirectories(root.resolve("Main"));
+ if( !imported ) Files.writeString(root.resolve("Main/Globals.smp"),globals);
+ new CodeGen(root.toString(),root.toString(),imported ? paths : null,"Main",src,126,true,TypeInteger.BOT)
+ .driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false);
+ assertEquals("",TestC.gcc(root+"/Main.o","",TestC.C_DRIVERS_DIR+"extern_data_import.c",
+ (String)null,new Ary<>(new String[]{dir+"/Globals.o"}),root+"/main"+(TestC.OS.startsWith("Windows") ? ".exe" : "")));
+ }
+ }
+
@Test public void testPrintingConstantPool() throws Exception {
com.seaofnodes.simple.codegen.PrintRegTestSupport.checkConstantPool();
}
@@ -312,6 +393,13 @@ return rez < buf# ? 0 : sys.libc._exit(-2);
}
@Test
+ public void testErrnoAccessor() throws IOException {
+ String src = "sys.libc.close(-1); return sys.libc.errno()==0;";
+ TestC.run(src,"errnoAccessor",new Ary<>(new String[]{SYS_BLDDIR}),
+ TestC.CALL_CONVENTION,null,null,"",-1);
+ }
+
+ @Test
public void testBubbles() throws IOException {
String src = Files.readString( Path.of("docs/examples/BubbleSort.smp"));
String exe = TestC.compile(src,"BubbleSort",new Ary<>(new String[]{SYS_BLDDIR}),
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter25/src/test/java/com/seaofnodes/simple/EvalRisc5.java
index a4cc7044..633e931e 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/EvalRisc5.java
@@ -252,7 +252,7 @@ public class EvalRisc5 {
case 2 -> (rs1 < rs2) ? 1 : 0;
case 3 -> (rs1 < rs2) ? 1 : 0;
case 4 -> rs1 ^ rs2;
- case 5 -> (ir & 0x40000000) != 0 ? (rs1 >>> (rs2 & 0x3F)) : (rs1 >> (rs2 & 0x3F));
+ case 5 -> (ir & 0x40000000) != 0 ? (rs1 >> (rs2 & 0x3F)) : (rs1 >>> (rs2 & 0x3F));
case 6 -> rs1 | rs2;
case 7 -> rs1 & rs2;
default -> rval;
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data.c b/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data.c
new file mode 100644
index 00000000..9325f65e
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data.c
@@ -0,0 +1,22 @@
+#include <stdint.h>
+#include <stdio.h>
+
+int32_t counter=7;
+int8_t small=-3;
+double fraction=1.25;
+
+int64_t bump(void) { counter+=5; return counter; }
+__attribute__((CALL_CONV)) extern int64_t test_global(void);
+
+int main(void) {
+ int64_t result=test_global();
+ if(result!=71515 || counter!=15 || small!=-2 || fraction!=1.75) {
+ printf("result=%lld counter=%d small=%d fraction=%g\n",
+ (long long)result,counter,small,fraction);
+ return 1;
+ }
+ // A second call must observe C's new values, not a Simple initialization copy.
+ counter=-2;
+ result=test_global();
+ return result!=-19394 || counter!=6 || small!=-1 || fraction!=2.25;
+}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data_import.c b/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data_import.c
new file mode 100644
index 00000000..f65e5c84
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/progs/extern_data_import.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <stdio.h>
+
+int32_t counter=7;
+__attribute__((CALL_CONV)) extern int64_t test_global(void);
+
+int main(void) {
+ int64_t result=test_global();
+ if(result!=710 || counter!=10) {
+ printf("result=%lld counter=%d\n",(long long)result,counter);
+ return 1;
+ }
+ return 0;
+}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/spill/README.md b/chapter25/src/test/java/com/seaofnodes/simple/spill/README.md
index fae44126..6c78d46f 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/spill/README.md
+++ b/chapter25/src/test/java/com/seaofnodes/simple/spill/README.md
@@ -27,11 +27,11 @@ Chapter 25 cannot parse all earlier sources unchanged. Adaptations are explicit:
All entries replay **through RegAlloc**, checking scheduled register constraints.
The historical phase column is provenance, not a promise to run those old native
-harnesses in Chapter 25. In particular, the adapted Bubble Sort still exposes a
-pre-existing ARM extern-data encoding limitation (`i32 errno="C"; return 0;` is
-sufficient to reproduce it). Allocation succeeds; ARM encoding does not. That
-separate failure remains in the backport queue. Do not count this corpus as
-historical runtime coverage.
+harnesses in Chapter 25. The adapted Bubble Sort retains its historical
+`i32 errno="C"` declaration for allocation comparability. Direct data bindings
+now encode on all three targets, but this declaration cannot link to a libc
+whose errno is thread-local or accessor-based. Current system-library code uses
+`libc.errno()` instead. Do not count this corpus as historical runtime coverage.
`SpillStats` then compiles the current system library through encoding at seed
456, and runs Chapter25Test with its existing seeds and native checks. Together