From b6765473a3ce3db943355abba8e8ff765a3f8a3b Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 10 Apr 2025 17:18:53 -0700 Subject: C tests check both Win64 qnd Sys5 NewX86 links against OS-specific `calloc`, uses OS-specific calling convention, and not the declared convention. Encoding bug, byte-store of SIL, DIL, BPL needs a blank REX. OBOB errors in Sys5 large-arg-count calling. --- .../simple/node/cpus/x86_64_v2/NewX86.java | 25 +++++---- .../simple/node/cpus/x86_64_v2/StoreX86.java | 4 +- .../simple/node/cpus/x86_64_v2/x86_64_v2.java | 59 +++++++++++++++------- 3 files changed, 56 insertions(+), 32 deletions(-) (limited to 'chapter21/src/main/java/com/seaofnodes') 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 13abd93b..01faba52 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 @@ -6,14 +6,21 @@ import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; public class NewX86 extends NewNode implements MachNode { + public static final String OS = System.getProperty("os.name"); + public static final RegMask ARG2 = OS.startsWith("Windows") + ? x86_64_v2.callWin64(TypeFunPtr.CALLOC,2) + : x86_64_v2.callSys5 (TypeFunPtr.CALLOC,2); + public static final RegMask ARG3 = OS.startsWith("Windows") + ? x86_64_v2.callWin64(TypeFunPtr.CALLOC,3) + : x86_64_v2.callSys5 (TypeFunPtr.CALLOC,3); + // A pre-zeroed chunk of memory. NewX86( NewNode nnn ) { super(nnn); } @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) { - // Any { int->int } signature will do, as they all pick the same registers - return i==1 ? x86_64_v2.callInMask(TypeFunPtr.CALLOC,3) : null; + return i==1 ? ARG2 : null; } @Override public RegMask outregmap(int i) { return i == 1 ? x86_64_v2.RAX_MASK : null; } @Override public RegMask outregmap() { return null; } @@ -21,18 +28,10 @@ public class NewX86 extends NewNode implements MachNode { @Override public void encoding( Encoding enc ) { enc.external(this,"calloc"); - short r1 = x86_64_v2.callInMask(TypeFunPtr.CALLOC,2).firstReg(); + // This has to call the *native* ABI, irregardless of how Simple is + // being compiled, because it links against the native calloc. // 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); - - + enc.add1(0xB8 + ARG3.firstReg()).add4(1); // 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/StoreX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java index 5fbd1f02..ac5de47d 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -57,8 +57,10 @@ public class StoreX86 extends MemOpX86 { src -= (short)x86_64_v2.XMM_OFFSET; enc.add1( decl==TypeFloat.F32 ? 0xF3 : 0xF2 ).add1(0x0F).add1(0x11); } else { + // byte stores from sil, dil, bpl, spl need a rex int log = decl.log_size(); - x86_64_v2.rexF(src,ptr,idx,log==3,enc); + if( log == 0 && src >= x86_64_v2.RSP ) enc.add1(x86_64_v2.rex(src,ptr,idx,false)); + else x86_64_v2.rexF(src,ptr,idx,log==3,enc); switch( log ) { case 0: enc .add1(0x88); break; case 1: enc.add1(0x66).add1(0x89); break; diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java index 2f70dc0c..7683177f 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -221,40 +221,63 @@ public class x86_64_v2 extends Machine { } // Win64 - max *4* args in registers of all kinds; after that on stack. - // Stack args land in increasing memory order. - // foo( int arg0, int arg1, int arg2, int arg3, int stk1, flt stk2, int stk3, ... ) + // Stack args land in increasing memory order with empty/mirror slots for + // every register. + // + // foo( int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, ... ) // // -- Prior Frame -- - // RPC - // stk3 - // stk2 - // stk1 + // i6 + // f5 + // i4 + // empty mirror, XMM3= f3 + // empty mirror, R08 = i2 + // empty mirror, XMM1= f1 + // empty mirror, RCX = i0 // -- Caller Frame; 16b align -- // RPC - // PAD + // PAD/ALIGN // -- Callee Frame; 16b align -- - static RegMask[] CALLINMASK_WIN64 = new RegMask[] { + static RegMask[] WIN64_CALL = new RegMask[] { RCX_MASK, RDX_MASK, R08_MASK, R09_MASK, }; - private static RegMask callWin64(TypeFunPtr tfp, int idx ) { - // idx 2,3,4,5 passed in registers, with stack slot mirrors - // idx >= 6 passed on stack, starting at slot#1 (#0 reserved for RPC) + static RegMask callWin64(TypeFunPtr tfp, int idx ) { + // idx 2,3,4,5 passed in registers, with stack slot mirrors. + // idx >= 6 passed on stack, starting at slot#1 (#0 reserved for RPC). if( idx >= 6 ) return new RegMask(MAX_REG+1/*RPC*/+(idx-2)); return tfp.arg(idx-2) instanceof TypeFloat - ? XMMS8[idx-2] - : CALLINMASK_WIN64[idx-2]; + ? XMMS8 [idx-2] + : WIN64_CALL[idx-2]; } static short maxArgSlotWin64(TypeFunPtr tfp) { return (short)(1/*RPC*/+ tfp.nargs()); } + // Sys5: max 6 GPRs and 8 FPRS filled first. Extra args land in increasing + // memory order as needed - no mirror space. + // + // foo( int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, ... ) + // RDI =i0, RSI =i2, RDX =i4, RCX =i6, R08 =i8, R09 =i10 + // XMM0=f1, XMM1=f3, XMM2=f5, XMM3=f7, XMM4=f9, XMM5=f11, XMM6=f13, XMM7=f15 + // + // -- Prior Frame -- + // f18 + // i18 + // f17 + // i16 + // i14 + // i12 + // -- Caller Frame; 16b align -- + // RPC + // PAD/ALIGN + // -- Callee Frame; 16b align -- // SystemV(param passing) - static RegMask[] CALLINMASK_SYSTEMV = new RegMask[] { + static RegMask[] SYS5_CALL = new RegMask[] { RDI_MASK, RSI_MASK, RDX_MASK, @@ -263,7 +286,7 @@ public class x86_64_v2 extends Machine { R09_MASK, }; - private static RegMask callSys5(TypeFunPtr tfp, int idx ) { + static RegMask callSys5(TypeFunPtr tfp, int idx ) { // First 6 integers passed in registers: rdi,rsi,rdx,rcx,r08,r09 // First 8 floats passed in registers: xmm0-xmm7 int icnt=0, fcnt=0; // Count of ints, floats @@ -273,8 +296,8 @@ public class x86_64_v2 extends Machine { } int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); return tfp.arg(idx-2) instanceof TypeFloat - ? fcnt<8 ? XMMS8 [fcnt] : new RegMask(MAX_REG+nstk) - : icnt<6 ? CALLINMASK_SYSTEMV[icnt] : new RegMask(MAX_REG+nstk); + ? fcnt<8 ? XMMS8 [fcnt] : new RegMask(MAX_REG+1/*RPC*/+nstk) + : icnt<6 ? SYS5_CALL[icnt] : new RegMask(MAX_REG+1/*RPC*/+nstk); } static short maxArgSlotSys5(TypeFunPtr tfp) { int icnt=0, fcnt=0; // Count of ints, floats @@ -283,7 +306,7 @@ public class x86_64_v2 extends Machine { else icnt++; } int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); - return (short)(1+nstk); + return (short)(1/*RPC*/+nstk); } // caller saved(systemv) -- cgit v1.2.3