summaryrefslogtreecommitdiff
path: root/chapter21/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-06 11:42:55 -0700
committerCliff Click <cliffc@acm.org>2025-04-06 11:42:55 -0700
commit819963deb617ea622a27918101867aab3c522c3c (patch)
treeafb33d90f469bdac6acd5f6b24dd1638617a4e1e /chapter21/src
parentabd2fc675d0fc29d5b525cdbe5b949e1c85b1e7e (diff)
downloadSimple-819963deb617ea622a27918101867aab3c522c3c.tar.gz
Simple-819963deb617ea622a27918101867aab3c522c3c.zip
More encoding bugs
Stack adjust needs REX. Boolean load/store same as U8 Calling calloc needs size of 1 in RCX, bytes in RDX
Diffstat (limited to 'chapter21/src')
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java14
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java1
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java1
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java3
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java57
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestC.java4
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c18
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp52
11 files changed, 98 insertions, 74 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
index 55b2b8af..923fa362 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
@@ -33,7 +33,7 @@ public class FunX86 extends FunNode implements MachNode {
if( sz == 0 ) return; // Skip if no frame adjust
// opcode: 0x83, addi rsp with immediate 8
- enc.add1( 0x83 );
+ enc.add1( x86_64_v2.REX_W ).add1( 0x83 );
enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, x86_64_v2.RSP) );
enc.add1(sz*8);
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
index 63bd8fb4..6e72a540 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
@@ -36,13 +36,13 @@ public class LoadX86 extends MemOpX86 {
x86_64_v2.rexF(dst, ptr, idx, decl != TypeInteger.U32 && decl != TypeFloat.F32 && decl != TypeFloat.F64, enc);
if( false ) ;
- else if( decl == TypeFloat.F32 ) enc.add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32
- else if( decl == TypeFloat.F64 ) enc.add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64
- else if( decl == TypeInteger.I8 ) enc.add1(0x0F).add1(0xBE); // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8
- else if( decl == TypeInteger.I16) enc.add1(0x0F).add1(0xBF); // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16
- else if( decl == TypeInteger.I32) enc.add1(0x63); // sign extend: REX.W + 63 /r MOVSXD r64, r/m32
- else if( decl == TypeInteger.U8 ) enc.add1(0x0F).add1(0xB6); // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8
- else if( decl == TypeInteger.U16) enc.add1(0x0F).add1(0xB7); // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16
+ else if( decl == TypeFloat.F32 ) enc.add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32
+ else if( decl == TypeFloat.F64 ) enc.add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64
+ else if( decl.isa(TypeInteger.I8)) enc.add1(0x0F).add1(0xBE); // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8
+ else if( decl == TypeInteger.I16 ) enc.add1(0x0F).add1(0xBF); // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16
+ else if( decl == TypeInteger.I32 ) enc.add1(0x63); // sign extend: REX.W + 63 /r MOVSXD r64, r/m32
+ else if( decl == TypeInteger.U8 ) enc.add1(0x0F).add1(0xB6); // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8
+ else if( decl == TypeInteger.U16 ) enc.add1(0x0F).add1(0xB7); // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16
// Covers U32, I64/BOT, TMP
else if( decl.log_size()>=2 ) enc.add1(0x8B); // zero extend: 8B /r MOV r32, r/m32
else throw Utils.TODO();
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
index 456d0093..13abd93b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
@@ -3,6 +3,7 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeFunPtr;
public class NewX86 extends NewNode implements MachNode {
// A pre-zeroed chunk of memory.
@@ -10,13 +11,28 @@ public class NewX86 extends NewNode implements MachNode {
@Override public String op() { return "alloc"; }
// Size and pointer result in standard calling convention; null for all the
// memory aliases edges
- @Override public RegMask regmap(int i) { return i == 1 ? x86_64_v2.RDI_MASK : null; }
+ @Override public RegMask regmap(int i) {
+ // Any { int->int } signature will do, as they all pick the same registers
+ return i==1 ? x86_64_v2.callInMask(TypeFunPtr.CALLOC,3) : null;
+ }
@Override public RegMask outregmap(int i) { return i == 1 ? x86_64_v2.RAX_MASK : null; }
@Override public RegMask outregmap() { return null; }
@Override public RegMask killmap() { return x86_64_v2.x86CallerSave(); }
@Override public void encoding( Encoding enc ) {
enc.external(this,"calloc");
+ short r1 = x86_64_v2.callInMask(TypeFunPtr.CALLOC,2).firstReg();
+ // ldi rcx,#1 // number of elements to calloc
+ enc.add1(0xB8 + r1).add4(1);
+
+ //enc.add1(x86_64_v2.rex(0, dst, 0));
+ //// opcode; 0x81 or 0x83; 0x69 or 0x6B
+ //enc.add1( opcode() + 2 );
+ //enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) );
+ //// immediate(4 bytes) 32 bits or (1 byte)8 bits
+ //enc.add1(_imm);
+
+
// E8 cd CALL rel32;
enc.add1(0xE8);
enc.add4(0); // offset
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
index bc4d5805..a9da15c6 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
@@ -20,7 +20,7 @@ public class RetX86 extends ReturnNode implements MachNode {
@Override public void encoding( Encoding enc ) {
int frameAdjust = ((FunX86)fun())._frameAdjust;
if( frameAdjust > 0 ) {
- enc.add1( 0x83 );
+ enc.add1( x86_64_v2.REX_W ).add1( 0x83 );
enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, x86_64_v2.RSP) );
enc.add1(frameAdjust*-8);
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index 167a931c..bd64bd81 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -44,6 +44,7 @@ public class TypeFunPtr extends TypeNil {
public static TypeFunPtr TEST = make((byte)2,TypeTuple.TEST,TypeInteger.BOT,1);
public static TypeFunPtr TEST0 = make((byte)3,TypeTuple.TEST,TypeInteger.BOT,3);
public static TypeFunPtr MAIN = make((byte)3,TypeTuple.MAIN,TypeInteger.BOT,-1);
+ public static TypeFunPtr CALLOC= make((byte)3,TypeTuple.CALLOC,TypeMemPtr.BOT,-1);
public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN); }
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
index 2d40a1cf..d3b19b52 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
@@ -17,6 +17,7 @@ public class TypeTuple extends Type {
public static final TypeTuple START= make(Type.CONTROL,TypeMem.TOP,TypeInteger.BOT);
public static final TypeTuple MAIN = make(TypeInteger.BOT);
public static final TypeTuple RET = make(Type.CONTROL,TypeMem.BOT,Type.BOTTOM);
+ public static final TypeTuple CALLOC = make(TypeInteger.BOT,TypeInteger.BOT);
public static final TypeTuple IF_BOTH = make(new Type[]{Type. CONTROL,Type. CONTROL});
public static final TypeTuple IF_NEITHER = make(new Type[]{Type.XCONTROL,Type.XCONTROL});
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index e011392d..a850b1b8 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -214,7 +214,8 @@ return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
@Test
public void sieveOEratosthenes() throws IOException {
- CodeGen code = new CodeGen(Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sieve.smp")));
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sieve.smp"));
+ CodeGen code = new CodeGen(src+"return sieve(arg);");
code.parse().opto();
assertEquals("return [int];", code.print());
assertEquals("int[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20));
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index dd38215c..3f764a4c 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -29,12 +29,6 @@ public class Chapter21Test {
assertEquals(stop, code._stop.toString());
}
- private static void testAllCPUs( String src, int spills, String stop ) {
- testCPU(src,"x86_64_v2", "SystemV",spills,stop);
- testCPU(src,"riscv" , "SystemV",spills,stop);
- testCPU(src,"arm" , "SystemV",spills,stop);
- }
-
@Test public void testBasic1() {
String src = "return arg | 2;";
@@ -44,6 +38,22 @@ public class Chapter21Test {
}
@Test
+ public void testArray1() throws IOException {
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/array1.smp"));
+ testCPU(src,"x86_64_v2", "SystemV",7,"return .[];");
+ testCPU(src,"riscv" , "SystemV",7,"return (add,.[],(mul,.[],1000));");
+ testCPU(src,"arm" , "SystemV",5,"return (add,.[],(mul,.[],1000));");
+ }
+
+ @Test
+ public void testFib() throws IOException {
+ String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/fib.smp"));
+ testCPU(src,"x86_64_v2", "SystemV",24,null);
+ testCPU(src,"riscv" , "SystemV",16,null);
+ testCPU(src,"arm" , "SystemV",16,null);
+ }
+
+ @Test
public void testNewtonFloat() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp"))
+ "flt farg = arg; return test_sqrt(farg) + test_sqrt(farg+2.0);";
@@ -52,7 +62,7 @@ public class Chapter21Test {
testCPU(src,"arm" , "SystemV",19,null);
}
- @Test public void testNewtonExport() throws Exception {
+ @Test public void testNewtonExport() throws IOException {
String result = """
0 0.000000
1 1.000000
@@ -76,36 +86,11 @@ public class Chapter21Test {
testCPU(src,"arm" , "SystemV", 6,null);
}
- @Test
- public void testStringExport() throws Exception { TestC.run("stringHash"); }
+ @Test public void testStringExport() throws IOException { TestC.run("stringHash"); }
- @Test
- public void testArray1() throws IOException {
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/array1.smp"));
- testCPU(src,"x86_64_v2", "SystemV",7,"return .[];");
- testCPU(src,"riscv" , "SystemV",7,"return (add,.[],(mul,.[],1000));");
- testCPU(src,"arm" , "SystemV",5,"return (add,.[],(mul,.[],1000));");
- }
-
- @Test
- public void testFib() throws IOException {
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/fib.smp"));
- testCPU(src,"x86_64_v2", "SystemV",24,null);
- testCPU(src,"riscv" , "SystemV",16,null);
- testCPU(src,"arm" , "SystemV",16,null);
- }
-
-
- // Read test case from disk.
- // TODO: exportELF not handling external calls yet
- @Ignore @Test
- public void testPersons() throws IOException {
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/Person.smp"));
- CodeGen code = new CodeGen(src);
- code.parse().opto().typeCheck().instSelect( "x86_64_v2", "SystemV").GCM().localSched().regAlloc().encode().exportELF("build/objs/Persons.o");
- //testCPU(src,"x86_64_v2", "Win64" ,3,null);
- //testCPU(src,"riscv" , "SystemV",1,null);
- //testCPU(src,"arm" , "SystemV",1,null);
+ @Test public void testSieve() throws IOException {
+ String primes = "[2, 3, ]";
+ TestC.run("sieve",primes);
}
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestC.java b/chapter21/src/test/java/com/seaofnodes/simple/TestC.java
index 121ace03..1cf1f36a 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestC.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestC.java
@@ -20,9 +20,9 @@ public abstract class TestC {
default -> throw Utils.TODO("Map Yer CPU Port Here");
};
- public static void run( String file ) throws Exception { run(file,""); }
+ public static void run( String file ) throws IOException { run(file,""); }
- public static void run( String file, String expected ) throws Exception {
+ public static void run( String file, String expected ) throws IOException {
run("src/test/java/com/seaofnodes/simple/progs",file,expected);
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c
new file mode 100644
index 00000000..8c28aea8
--- /dev/null
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdbool.h>
+
+typedef struct AryInt {
+ unsigned int len;
+ unsigned int data[];
+} AryInt;
+
+extern AryInt sieve(int N);
+
+int main() {
+ AryInt ps = sieve(10);
+ printf("[");
+ for( int i=0; i<ps.len; i++ )
+ printf("%d, ",ps.data[i]);
+ printf("]");
+ return 0;
+}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
index 0b6f56ed..c5c3824a 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
@@ -1,29 +1,31 @@
// -*- mode: java; -*-
// The main Sieve array
-bool[] !ary = new bool[arg];
-// The primes less than arg
-int[] !primes = new int[arg>>1];
-// Number of primes so far, searching at index p
-int nprimes = 0, p=2;
-// Find primes while p^2 < arg
-while( p*p < arg ) {
- // skip marked non-primes
- while( ary[p] ) p++;
- // p is now a prime
- primes[nprimes++] = p;
- // Mark out the rest non-primes
- for( int i = p + p; i < ary#; i+= p )
- ary[i] = true;
- p++;
-}
-
-// Now just collect the remaining primes, no more marking
-for( ; p < arg; p++ )
- if( !ary[p] )
+val sieve = { int N ->
+ bool[] !ary = new bool[N];
+ // The primes less than N
+ int[] !primes = new int[N>>1];
+ // Number of primes so far, searching at index p
+ int nprimes = 0, p=2;
+ // Find primes while p^2 < N
+ while( p*p < N ) {
+ // skip marked non-primes
+ while( ary[p] ) p++;
+ // p is now a prime
primes[nprimes++] = p;
+ // Mark out the rest non-primes
+ for( int i = p + p; i < ary#; i+= p )
+ ary[i] = true;
+ p++;
+ }
+
+ // Now just collect the remaining primes, no more marking
+ for( ; p < N; p++ )
+ if( !ary[p] )
+ primes[nprimes++] = p;
-// Copy/shrink the result array
-int[] !rez = new int[nprimes];
-for( int j=0; j < nprimes; j++ )
- rez[j] = primes[j];
-return rez;
+ // Copy/shrink the result array
+ int[] !rez = new int[nprimes];
+ for( int j=0; j < nprimes; j++ )
+ rez[j] = primes[j];
+ return rez;
+};