From 819963deb617ea622a27918101867aab3c522c3c Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sun, 6 Apr 2025 11:42:55 -0700 Subject: More encoding bugs Stack adjust needs REX. Boolean load/store same as U8 Calling calloc needs size of 1 in RCX, bytes in RDX --- .../simple/node/cpus/x86_64_v2/FunX86.java | 2 +- .../simple/node/cpus/x86_64_v2/LoadX86.java | 14 +++--- .../simple/node/cpus/x86_64_v2/NewX86.java | 18 ++++++- .../simple/node/cpus/x86_64_v2/RetX86.java | 2 +- .../com/seaofnodes/simple/type/TypeFunPtr.java | 1 + .../java/com/seaofnodes/simple/type/TypeTuple.java | 1 + .../java/com/seaofnodes/simple/Chapter15Test.java | 3 +- .../java/com/seaofnodes/simple/Chapter21Test.java | 57 ++++++++-------------- .../src/test/java/com/seaofnodes/simple/TestC.java | 4 +- .../test/java/com/seaofnodes/simple/progs/sieve.c | 18 +++++++ .../java/com/seaofnodes/simple/progs/sieve.smp | 52 ++++++++++---------- 11 files changed, 98 insertions(+), 74 deletions(-) create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c (limited to 'chapter21/src') 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 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;"; @@ -43,6 +37,22 @@ public class Chapter21Test { testCPU(src,"arm" , "SystemV",0,"return (ori,arg);"); } + @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")) @@ -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 +#include + +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>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; +}; -- cgit v1.2.3