diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-08 16:52:27 -0700 |
| commit | d32f97238c903765dec4e9a9f3cbfa5fd12cded6 (patch) | |
| tree | a5ac731801ef7066bab6359c4e85c2bdd20082a6 /src/main/java/com/seaofnodes/simple/node/cpus | |
| parent | b5ebb2032aa04cf4506d533127d373d4cf5a25c6 (diff) | |
| download | Simple-linear.tar.gz Simple-linear.zip | |
Chapter 25: Modules, Separate Compilation, and SSA Constructionlinear
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: Symious <14933944+symious@users.noreply.github.com>
Co-authored-by: Jun Kawasaki <jun784@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/main/java/com/seaofnodes/simple/node/cpus')
41 files changed, 447 insertions, 349 deletions
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java index 127f17ff..31bbde86 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java @@ -9,9 +9,11 @@ import com.seaofnodes.simple.util.Utils; // Jump on flags, uses flags public class BranchARM extends IfNode implements MachNode, RIPRelSize { String _bop; - BranchARM(IfNode iff, String bop ) { + final boolean _fp; + BranchARM(IfNode iff, String bop, boolean fp ) { super(iff); _bop = bop; + _fp = fp; } @Override public String op() { return "j"+_bop; } @Override public String label() { return op(); } @@ -36,7 +38,7 @@ public class BranchARM extends IfNode implements MachNode, RIPRelSize { // by comparison (or sub). No need for regs because it uses flags if( in(1)!=null ) { // B.cond - enc.add4( Arm64.b_cond(Arm64.OP_BRANCH, 0, Arm64.make_condition(_bop)) ); + enc.add4( Arm64.b_cond(Arm64.OP_BRANCH, 0, Arm64.make_condition(_bop, _fp)) ); } else { if( _bop=="!=" ) return; // Inverted, no code enc.add4(Arm64.b(Arm64.OP_UJMP, 0)); @@ -56,7 +58,7 @@ public class BranchARM extends IfNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { assert !( in(1)==null && _bop=="!=" ); // Inverted never-node, no code no patch if( opLen==4 ) { - enc.patch4(opStart,Arm64.b_cond(Arm64.OP_BRANCH, delta, Arm64.make_condition(_bop))); + enc.patch4(opStart,Arm64.b_cond(Arm64.OP_BRANCH, delta, Arm64.make_condition(_bop, _fp))); } else { throw Utils.TODO(); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java index e1717cb3..4de28f3a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java @@ -14,8 +14,7 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize { _inputs.pop(); // Pop constant target assert tfp.isConstant(); _tfp = tfp; - FunNode fun = CodeGen.CODE.link(tfp); - _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + _name = CodeGen.CODE.funcName(tfp.fidx()); } @Override public String op() { return "call"; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FltARM.java index dc21e075..db2540f7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FltARM.java @@ -4,21 +4,22 @@ import com.seaofnodes.isa.Arm64; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; -import com.seaofnodes.simple.type.TypeFloat; import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; //FMOV (scalar, immediate) //Floating-point move immediate. -public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { - FloatARM(ConstantNode con) { super(con); } +public class FltARM extends ConstantNode implements MachNode, RIPRelSize { + final String _ext; + FltARM( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ld8"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return arm.DMASK; } @Override public boolean isClone() { return true; } - @Override public FloatARM copy() { return new FloatARM(this); } + @Override public FltARM copy() { return new FltARM(this,_ext); } @Override public void encoding( Encoding enc ) { + if( _ext!=null ) throw Utils.TODO(); enc.largeConstant(this,_con,0,-1/*TODO: ARM-style ELF patching*/); short dst = (short)(enc.reg(this) - arm.D_OFFSET); enc.add4(Arm64.load_pc(Arm64.OPF_ARM, 0, dst)); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java index 7a9e74c6..72b76edd 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java @@ -7,19 +7,22 @@ import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Integer constants public class IntARM extends ConstantNode implements MachNode { - IntARM( ConstantNode con ) { super(con); } + final String _ext; + IntARM( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ldi"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return arm.WMASK; } @Override public boolean isClone() { return true; } - @Override public IntARM copy() { return new IntARM(this); } + @Override public IntARM copy() { return new IntARM(this,_ext); } @Override public void encoding( Encoding enc ) { + if( _ext!=null ) throw Utils.TODO(); short self = enc.reg(this); long x = _con==Type.NIL ? 0 : ((TypeInteger)_con).value(); Arm64.constant(enc,self,x); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java index 8fc22a67..53494092 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java @@ -25,7 +25,7 @@ public class LoadARM extends MemOpARM { // ldr(immediate - unsigned offset) | ldr(register) @Override public void encoding( Encoding enc ) { - ldst_encode(enc, OP_LOADS[Integer.numberOfTrailingZeros(size())], OP_LOAD_RS[_declaredType.log_size()], this, size()); + ldst_encode(enc, OP_LOADS[Integer.numberOfTrailingZeros(size())], OP_LOAD_RS[_con.log_size()], this, size()); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(","); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java index dfbe5e06..14eaf510 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java @@ -7,13 +7,13 @@ import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.util.SB; -import com.seaofnodes.simple.util.Utils; import java.lang.StringBuilder; public abstract class MemOpARM extends MemOpNode implements MachNode { final int _off; // Limit 9 bits sized, or (13 bits<<logsize) unsigned final int _imm; // Limit ? bits - final char _sz = (char)('0'+(1<<_declaredType.log_size())); + final int _bytes; + final char _sz; MemOpARM(MemOpNode mop, Node ptr, Node idx, int off, int imm) { super(mop,mop); assert ptr._type instanceof TypeMemPtr && !(ptr instanceof AddNode); @@ -22,6 +22,8 @@ public abstract class MemOpARM extends MemOpNode implements MachNode { _inputs.setX(3, idx); _off = off; _imm = imm; + _bytes = mop instanceof StoreNode st ? st.storeSize() : 1<<_con.log_size(); + _sz = (char)('0'+_bytes); } // Store-based flavors have a value edge @@ -35,10 +37,10 @@ public abstract class MemOpARM extends MemOpNode implements MachNode { @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); } - @Override public Type compute() { throw Utils.TODO(); } - @Override public Node idealize() { throw Utils.TODO(); } + @Override public Type compute() { throw new AssertionError("Do not call compute on "+getClass().getSimpleName()); } + @Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); } - int size() { return 1<<_declaredType.log_size(); } + int size() { return _bytes; } // Wider mask to store both GPRs and FPRs @Override public RegMask regmap(int i) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java index 7110df62..8bb8983e 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java @@ -32,7 +32,8 @@ public class NewARM extends NewNode implements MachNode, RIPRelSize { } // General form: "alloc #bytes PC" @Override public void asm(CodeGen code, SB sb) { - sb.p("ldi x0=#1\n"); + sb.p("\n"); // Multi-op trigger + sb.p("ldi ").p(code._mach.regs()[_arg2Reg]).p(" = #1\n"); sb.p("call #calloc"); } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java index afbbd3bf..e5b06c39 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java @@ -9,12 +9,14 @@ import com.seaofnodes.simple.util.SB; // e.g CSET, stores flag info into GPRS after compare public class SetARM extends MachConcreteNode implements MachNode { final String _bop; // One of <,<=,== - SetARM(Node cmp, String bop) { + final boolean _fp; // FP compare (unsigned encoding) + SetARM(Node cmp, String bop, boolean fp) { super(cmp); _inputs.setLen(1); // Pop the cmp inputs // Replace with the matched cmp _inputs.push(cmp); _bop = bop; + _fp = fp; } @Override public String op() { return "set"+_bop; } @Override public RegMask regmap(int i) { assert i==1; return arm.FLAGS_MASK; } @@ -22,7 +24,7 @@ public class SetARM extends MachConcreteNode implements MachNode { @Override public void encoding( Encoding enc ) { // Using RM==RN==31 implies a *zero* value, not R31. - int body = Arm64.cset(Arm64.OP_CSET,0b11111, Arm64.make_condition(_bop), 0b011111, enc.reg(this)); + int body = Arm64.cset(Arm64.OP_CSET,0b11111, Arm64.make_condition(_bop, _fp), 0b011111, enc.reg(this)); enc.add4(body); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java index f93f0f24..dcfeb5d8 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java @@ -9,7 +9,7 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class SplitARM extends SplitNode { - SplitARM(String kind, byte round) { super(kind,round,new Node[2]);} + SplitARM(LRG lrg, String kind, byte round) { super(lrg,kind,round,new Node[2]);} @Override public RegMask regmap(int i) { return arm.SPLIT_MASK; } @Override public RegMask outregmap() { return arm.SPLIT_MASK; } @@ -25,7 +25,7 @@ public class SplitARM extends SplitNode { if(src >= arm.MAX_REG) { throw Utils.TODO(); } - int off = enc._fun.computeStackOffset(enc._code,dst); + int off = fun(enc).computeStackOffset(enc._code,dst); if( srcX ) src -= arm.D_OFFSET; enc.add4(Arm64.load_str_imm(Arm64.OP_STORE_IMM_64, off, arm.RSP, src, 8)); return; @@ -33,7 +33,7 @@ public class SplitARM extends SplitNode { if(src >= arm.MAX_REG) { // Load from SP - int off = enc._fun.computeStackOffset(enc._code,src); + int off = fun(enc).computeStackOffset(enc._code,src); if( dstX ) dst -= arm.D_OFFSET; enc.add4(Arm64.load_str_imm(Arm64.OP_LOAD_IMM_64, off, arm.RSP, dst, 8)); return; @@ -57,10 +57,4 @@ public class SplitARM extends SplitNode { enc.add4(Arm64.f_mov_general(Arm64.OP_FMOV, 0b01, 0, 0b110, src - arm.D_OFFSET, dst)); } } - - // General form: "mov dst = src" - @Override public void asm(CodeGen code, SB sb) { - FunNode fun = code._encoding==null ? null : code._encoding._fun; - sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); - } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java index 2cc54f76..0b90ac8b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java @@ -28,7 +28,7 @@ public class StoreARM extends MemOpARM { private static final int[] OP_STORE_RS = new int[]{ Arm64.OP_STORE_R_8, Arm64.OP_STORE_R_16, Arm64.OP_STORE_R_32, Arm64.OP_STORE_R_64, }; @Override public void encoding( Encoding enc ) { - ldst_encode(enc, OP_STORES[Integer.numberOfTrailingZeros(size())], OP_STORE_RS[_declaredType.log_size()], val(), size()); + ldst_encode(enc, OP_STORES[Integer.numberOfTrailingZeros(size())], OP_STORE_RS[Integer.numberOfTrailingZeros(_bytes)], val(), size()); } @Override public void asm(CodeGen code, SB sb) { asm_address(code,sb).p(","); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 98a56089..a053ba46 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -2,28 +2,30 @@ package com.seaofnodes.simple.node.cpus.arm; import com.seaofnodes.isa.Arm64; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.MachNode; -import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; -public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { - TFPARM( ConstantNode con ) { super(con); } +public class TFPARM extends FunPtrNode implements MachNode, RIPRelSize { + final String _ext; + // Pointer to a Simple function + TFPARM( FunPtrNode fptr ) { super(fptr); _ext = null; } + // Pointer to an Extern "C" function + TFPARM( TypeFunPtr fptr, String ext ) { super(fptr,CodeGen.CODE._start,null); _type = fptr; _ext = ext; } @Override public String op() { return "ldx"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return arm.WMASK; } @Override public boolean isClone() { return true; } - @Override public TFPARM copy() { return new TFPARM(this); } + @Override public TFPARM copy() { return new TFPARM((TypeFunPtr)_con,_ext); } @Override public void encoding( Encoding enc ) { - enc.relo(this); - short self = enc.reg(this); + if( _ext==null ) enc.relo(this); // Internal patch + else enc.external(this,_ext); // ELF-file external patch + short dst = enc.reg(this); // adrp x0, 0 - int adrp = Arm64.adrp(1,0, Arm64.OP_ADRP, 0,self); + enc.add4(Arm64.adrp(1,0, Arm64.OP_ADRP, 0,dst)); // add x0, x0, 0 - enc.add4(adrp); - arm.imm_inst(enc,Arm64.OPI_ADD,0, 0); + arm.imm_inst(enc,Arm64.OPI_ADD,0, dst); } @Override public byte encSize(int delta) { @@ -34,15 +36,7 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); if(opLen == 8 ) { - // ARM encoding delta is from PC & 0xFFF - int target = opStart+delta; - int base = opStart & ~0xFFF; - delta = target-base; - int adrp_delta = delta >> 12; - // patch upper 20 bits via adrp - enc.patch4(opStart, Arm64.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); - // low 12 bits via add - enc.patch4(opStart+4, Arm64.imm_inst_l(Arm64.OPI_ADD, delta & 0xfff, rpc)); + arm.patch_adrp_add(enc, opStart, delta, rpc); } else { // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); @@ -51,7 +45,7 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); - _con.print(sb.p(reg).p(" #")); + _type.print(sb.p(reg).p(" #")); } @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java index d1cafa96..b2531f97 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -10,14 +10,16 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { - TMPARM( ConstantNode con ) { super(con); } + final String _ext; + TMPARM( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ldp"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return arm.WMASK; } @Override public boolean isClone() { return true; } - @Override public TMPARM copy() { return new TMPARM(this); } + @Override public TMPARM copy() { return new TMPARM(this,_ext); } @Override public void encoding( Encoding enc ) { - enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + if( _ext!=null ) enc.externalData(this,_ext); + else enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); short dst = enc.reg(this); // adrp x0, 0 enc.add4(Arm64.adrp(1,0, Arm64.OP_ADRP, 0,dst)); @@ -33,15 +35,7 @@ public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short dst = enc.reg(this); if(opLen == 8 ) { - // ARM encoding delta is from PC & 0xFFF - int target = opStart+delta; - int base = opStart & ~0xFFF; - delta = target-base; - int adrp_delta = delta >> 12; - // patch upper 20 bits via adrp - enc.patch4(opStart, Arm64.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); - // low 12 bits via add - enc.patch4(opStart+4, Arm64.imm_inst_l(Arm64.OPI_ADD, delta & 0xfff, dst)); + arm.patch_adrp_add(enc, opStart, delta, dst); } else { throw Utils.TODO(); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 32c1e2fc..660f1559 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -212,6 +212,14 @@ public class arm extends Machine { enc.add4(body); } + public static void patch_adrp_add(Encoding enc, int opStart, int delta, int rd) { + int target = opStart + delta; + int pageDelta = ((target & ~0xFFF) - (opStart & ~0xFFF)) >> 12; + int imm21 = pageDelta & 0x1FFFFF; + enc.patch4(opStart , Arm64.adrp(1, imm21 & 3, OP_ADRP, imm21 >>> 2, rd)); + enc.patch4(opStart+4, Arm64.imm_inst_l(OPI_ADD, target & 0xFFF, rd)); + } + public static void f_cmp(Encoding enc, Node n) { short reg1 = (short)(enc.reg(n.in(1))-D_OFFSET); short reg2 = (short)(enc.reg(n.in(2))-D_OFFSET); @@ -225,10 +233,16 @@ public class arm extends Machine { if( idx==1 ) return null; // Count floats in signature up to index if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + boolean hidden = hiddenSelf(tfp); + int sigidx = idx-2; + if( hidden ) { + if( sigidx==0 ) return null; + sigidx--; + } // Count floats in signature up to index int fcnt=0; - for( int i=2; i<idx; i++ ) - if( tfp.arg(i-2) instanceof TypeFloat) + for( int i=hidden ? 1 : 0; i<idx-2; i++ ) + if( tfp.arg(i) instanceof TypeFloat) fcnt++; // Floats up to XMMS in XMM registers if( tfp.arg(idx-2) instanceof TypeFloat ) { @@ -236,24 +250,27 @@ public class arm extends Machine { return XMMS[fcnt]; } else { RegMask[] cargs = CALLINMASK; - if( idx-2-fcnt < cargs.length ) - return cargs[idx-2-fcnt]; + if( sigidx-fcnt < cargs.length ) + return cargs[sigidx-fcnt]; } // Pass on stack slot (8 and higher) if( maxArgSlot>0 ) throw Utils.TODO(); - return new RegMask(MAX_REG + 1 + (idx - 2)); + return new RegMask(MAX_REG + 1 + sigidx); } // Return the max stack slot used by this signature, or 0 @Override public short maxArgSlot( TypeFunPtr tfp ) { int icnt=0, fcnt=0; // Count of ints, floats - for( int i=0; i<tfp.nargs(); i++ ) { + for( int i=hiddenSelf(tfp) ? 1 : 0; i<tfp.nargs(); i++ ) { if( tfp.arg(i) instanceof TypeFloat ) fcnt++; else icnt++; } int nstk = Math.max(icnt-8,0)+Math.max(fcnt-8,0); return (short)nstk; } + private static boolean hiddenSelf(TypeFunPtr tfp) { + return tfp.nargs() > 0 && tfp.arg(0) == TypePtr.PTR; + } private static final long CALLEE_SAVE = 1L<<X19 | @@ -271,7 +288,7 @@ public class arm extends Machine { @Override public int rpc() { return X30; } // Create a split op; any register to any register, including stack slots - @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitARM(kind,round); } + @Override public SplitNode split(LRG lrg, String kind, byte round) { return new SplitARM(lrg,kind,round); } // Return a MachNode unconditional branch @Override public CFGNode jump() { @@ -281,30 +298,33 @@ public class arm extends Machine { // Instruction selection @Override public Node instSelect(Node n ) { return switch( n ) { - case AddFNode addf -> new AddFARM(addf); case AddNode add -> add(add); case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CallNode call -> call(call); - case CastNode cast -> new CastMach(cast); + case PtrToIntNode ptr -> new PtrToIntMach(ptr); + case GuardNode guard -> new GuardMach(guard); case CallEndNode cend-> new CallEndMach(cend); case CProjNode c -> new CProjNode(c); case ConstantNode con-> con(con); - case DivFNode divf -> new DivFARM(divf); - case DivNode div -> new DivARM(div); + case DivNode div -> div.mode()==2 ? new DivFARM(div) : new DivARM(div); + case EscapeNode esc -> new EscapeNode(esc); case FunNode fun -> new FunARM(fun); + case FunPtrNode fptr -> fptr(fptr); case IfNode iff -> jmp(iff); case LoadNode ld -> ld(ld); case MemMergeNode mem-> new MemMergeNode(mem); - case MinusNode neg -> new NegARM(neg); - case MulFNode mulf -> new MulFARM(mulf); - case MulNode mul -> new MulARM(mul); + case MinusNode neg -> { + if( neg.mode()==2 ) throw Utils.TODO(); + yield new NegARM(neg); + } + case MulNode mul -> mul.mode()==2 ? new MulFARM(mul) : new MulARM(mul); case NewNode nnn -> new NewARM(nnn); case NotNode not -> new NotARM(not); case OrNode or -> or(or); case ParmNode parm -> new ParmARM(parm); case BulkMemPhiNode phi -> new BulkMemPhiNode(phi); - case MemPhiNode phi -> new MemPhiNode(phi); + case MemPhiNode phi -> new MemPhiNode(phi); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); case ReadOnlyNode read -> new ReadOnlyMach(read); @@ -312,11 +332,12 @@ public class arm extends Machine { case SarNode sar -> asr(sar); case ShlNode shl -> lsl(shl); case ShrNode shr -> lsr(shr); + case StartCUNode start -> new StartCUNode(start); + case StopCUNode stop -> new StopCUNode(stop); case StartNode start -> new StartNode(start); case StopNode stop -> new StopNode(stop); case StoreNode st -> st(st); - case SubFNode subf -> new SubFARM(subf); - case SubNode sub -> sub(sub); + case SubNode sub -> sub.mode()==2 ? new SubFARM(sub) : sub(sub); case ToFloatNode tfn -> new I2F8ARM(tfn); case ToIntegerNode cvt -> new F8ToIARM(cvt); case XorNode xor -> xor(xor); @@ -329,7 +350,7 @@ public class arm extends Machine { private Node cmp(BoolNode bool){ Node cmp = _cmp(bool); - return new SetARM(cmp, bool.op()); + return new SetARM(cmp, bool.op(), cmp instanceof CmpFARM); } private Node _cmp(BoolNode bool) { if( bool.isFloat() ) @@ -348,13 +369,18 @@ public class arm extends Machine { // Most general arith ops will also set flags, which the Jmp needs directly. // Loads do not set the flags, and will need an explicit TEST String op = "!="; - if( iff.in(1) instanceof BoolNode bool ) op = bool.op(); + boolean fp = false; + if( iff.in(1) instanceof BoolNode bool ) { op = bool.op(); fp = bool.isFloat(); } else if( iff.in(1)==null ) op = "=="; // Never-node cutout - else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); - return new BranchARM(iff, op); + else iff.setDef(1, new BoolNode.NE(iff.in(1), + ConstantNode.raw(TypeInteger.ZERO), + (byte)(iff.in(1)._type instanceof TypeFloat ? 2 : 1))); + return new BranchARM(iff, op, fp); } private Node add(AddNode add) { + if( add.mode()==2 ) + return new AddFARM(add); return add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti) ? new AddIARM(add, (int)ti.value()) : new AddARM(add); @@ -367,22 +393,30 @@ public class arm extends Machine { } private Node con( ConstantNode con ) { - if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs + if( !con._con.isConstant() ) + return ConstantNode.raw(con); // Default unknown caller inputs + String ext = con instanceof ExternNode ext0 ? ext0._extern : null; return switch( con._con ) { - case TypeInteger ti -> new IntARM(con); - case TypeFloat tf -> new FloatARM(con); - case TypeFunPtr tfp -> new TFPARM(con); - case TypeMemPtr tmp -> new TMPARM(con); + case TypeInteger ti -> new IntARM(con,ext); + case TypeFloat tf -> new FltARM(con,ext); + case TypeMemPtr tmp -> new TMPARM(con,ext); + case TypeFunPtr tfp -> new TFPARM(tfp,ext); case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case Type t -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con); + case Type t -> t==Type.NIL ? new IntARM(con,ext) : ConstantNode.raw(con); }; } + private Node fptr( FunPtrNode con ) { + return new TFPARM(con); + } + private Node call(CallNode call){ - return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp - ? new CallARM(call, tfp) - : new CallRRARM(call); + return call.fptr() instanceof FunPtrNode fptr + ? new CallARM(call, (TypeFunPtr)fptr._type) + : call.fptr() instanceof ConstantNode con + ? new CallARM(call, (TypeFunPtr)con._type) + : new CallRRARM(call); } private Node or(OrNode or) { @@ -424,6 +458,12 @@ public class arm extends Machine { : new LsrARM(lsr); } + private Node prj(ProjNode prj) { + TypeInteger ret = cReturn(prj); + if( ret!=null ) return new ExtendARM(prj,ret); + return prj.in(0) instanceof StartNode ? new ProjNode(prj) : new ProjARM(prj); + } + private static int off; private static Node idx; private Node st(StoreNode st) { @@ -449,9 +489,4 @@ public class arm extends Machine { return mop; } - private Node prj(ProjNode prj) { - TypeInteger ret = cReturn(prj); - return ret==null ? new ProjARM(prj) : new ExtendARM(prj,ret); - } - } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java index 14581111..59bad64e 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java @@ -2,19 +2,19 @@ package com.seaofnodes.simple.node.cpus.riscv; import com.seaofnodes.isa.RiscV; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.FunPtrNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; // Add upper 20bits to PC. Immediate comes from the relocation info. -public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { - AUIPC( Type tfp ) { super(tfp); } +public class AUIPC extends FunPtrNode implements MachNode, RIPRelSize { + AUIPC( FunPtrNode fptr ) { super(fptr); } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public AUIPC copy() { return new AUIPC(_con); } + @Override public AUIPC copy() { return new AUIPC(this); } @Override public String op() { return "auipc"; } @Override public void encoding( Encoding enc ) { enc.relo(this); @@ -37,7 +37,6 @@ public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); sb.p(reg).p(" = PC+#"); - if( _con == null ) sb.p("---"); - else _con.print(sb); + _type.print(sb); } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java index f0ad8e88..b1426a3f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java @@ -15,8 +15,7 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { assert tfp.isConstant(); _inputs.pop(); // Pop constant target _tfp = tfp; - FunNode fun = CodeGen.CODE.link(tfp); - _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + _name = CodeGen.CODE.funcName(tfp.fidx()); } @Override public String op() { return "call"; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java index 5eee596d..cda4bc79 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java @@ -14,7 +14,7 @@ public class CallRRISC extends CallNode implements MachNode { ? riscv.RMASK // Function call target : riscv.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument } - @Override public RegMask outregmap() { return null; } + @Override public RegMask outregmap() { return riscv.RPC_MASK; } @Override public void encoding( Encoding enc ) { short rpc = enc.reg(this); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java index 51ddc9db..a110d156 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java @@ -9,12 +9,13 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { - FltRISC(ConstantNode con) { super(con); } + final String _ext; + FltRISC( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ld8"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.FMASK; } @Override public boolean isClone() { return true; } - @Override public FltRISC copy() { return new FltRISC(this); } + @Override public FltRISC copy() { return new FltRISC(this,_ext); } @Override public void encoding( Encoding enc ) { enc.largeConstant(this,_con, 0, -1); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java index 23ac8481..dd4a02a3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java @@ -5,21 +5,23 @@ import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Special instruction for loading 8 byte constants from the constant pool. public class Int8RISC extends ConstantNode implements MachNode, RIPRelSize { - public Int8RISC(ConstantNode con) { super(con); } - + final String _ext; + Int8RISC( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ld8"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public Int8RISC copy() { return new Int8RISC(this); } + @Override public Int8RISC copy() { return new Int8RISC(this,_ext); } @Override public byte encSize(int delta) { return 8; } @Override public void encoding( Encoding enc ) { + if( _ext!=null ) throw Utils.TODO(); short dst = enc.reg(this); short tmp = (short)riscv.T6; enc.largeConstant(this,_con, 0, -1); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java index 9088abbd..35d2bc65 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java @@ -11,7 +11,7 @@ import com.seaofnodes.simple.util.SB; // 12-bit integer constant. Larger constants are made up in the instruction // selection by adding with a LUI. public class IntRISC extends ConstantNode implements MachNode { - public IntRISC(ConstantNode con) { super(con); } + IntRISC(ConstantNode con) { super(con); } @Override public String op() { return "ldi"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java index 2e3dfd8d..e9f3ec02 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java @@ -3,7 +3,9 @@ package com.seaofnodes.simple.node.cpus.riscv; import com.seaofnodes.isa.RiscV; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Load memory addressing on RISC // Support imm, reg(direct), or reg+off(indirect) addressing @@ -22,6 +24,39 @@ public class LoadRISC extends MemOpRISC { if( dst >= riscv.F_OFFSET ) dst -= riscv.F_OFFSET; enc.add4(RiscV.i_type(op, dst, func3(), ptr, _off)); } + @Override int func3() { + int func3 = -1; + // no unsigned flavour for store, so both signed and unsigned trigger the same + Type declType = _con; + if( declType == TypeInteger. I8 ) func3=0; // LB + if( declType == TypeInteger.I16 ) func3=1; // LH + if( declType == TypeInteger.I32 ) func3=2; // LW + if( declType == TypeInteger.BOT ) func3=3; // LD + if( declType == TypeInteger. U8 ) func3=4; // LBU + if( declType == TypeInteger.BOOL) func3=4; // LBU + if( declType == TypeInteger.U16 ) func3=5; // LHU + if( declType == TypeInteger.U32 ) func3=6; // LWU + if( declType instanceof TypeInteger ti ) { + if( -128 <= ti._min && ti._max < 128 ) func3 = 0; // LB + } + + // float + if( declType == TypeFloat.F32) func3 = 2; // fLW fSW + if( declType == TypeFloat.F64) func3 = 3; // fLD fSD + + if( declType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) + if( declType instanceof TypeFunPtr) func3 = 3; // 8 byte function pointers + if( declType instanceof TypeConAry ary ) + func3 = switch( ary.log_size() ) { + case 0 -> 4; // LBU + case 1 -> 5; // LHU + case 2 -> 2; // LW + case 3 -> 3; // LD + default -> throw Utils.TODO("RISC-V constant-array load for "+declType); + }; + if( func3 == -1 ) throw Utils.TODO("RISC-V load for "+declType); + return func3; + } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(","); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java index adf21848..e0bbc219 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -11,6 +11,7 @@ import com.seaofnodes.simple.type.*; public abstract class MemOpRISC extends MemOpNode implements MachNode { final int _off; // Limit 12 bits final char _sz; + final int _bytes; MemOpRISC(MemOpNode mop, Node base, int off, Node val) { super(mop,mop); assert base._type instanceof TypeMemPtr; @@ -18,7 +19,8 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { _inputs.setX(3, null); // Never an index _inputs.setX(4, val ); _off = off; - _sz = (char)('0'+(1<<_declaredType.log_size())); + _bytes = mop instanceof StoreNode st ? st.storeSize() : 1<<_con.log_size(); + _sz = (char)('0'+_bytes); } @Override public String label() { return op(); } @@ -26,42 +28,11 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); } - @Override public Type compute() { throw Utils.TODO(); } - @Override public Node idealize() { throw Utils.TODO(); } + @Override public Type compute() { throw new AssertionError("Do not call compute on "+getClass().getSimpleName()); } + @Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); } // func3 is based on load/store size and extend - int func3() { - int func3 = -1; - // no unsigned flavour for store, so both signed and unsigned trigger the same - if(this instanceof StoreRISC) { - if( _declaredType == TypeInteger. I8 || _declaredType == TypeInteger.U8 || _declaredType == TypeInteger.BOOL) func3=0; // SB - if( _declaredType == TypeInteger.I16 || _declaredType == TypeInteger.U16 ) func3=1; // SH - if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 ) func3=2; // SW - if( _declaredType instanceof TypeMemPtr) func3=3; // SD - if( _declaredType == TypeInteger.BOT ) func3=3; // SD - if( func3 == -1 ) throw Utils.TODO(); - return func3; - } - if( _declaredType == TypeInteger. I8 ) func3=0; // LB - if( _declaredType == TypeInteger.I16 ) func3=1; // LH - if( _declaredType == TypeInteger.I32 ) func3=2; // LW - if( _declaredType == TypeInteger.BOT ) func3=3; // LD - if( _declaredType == TypeInteger. U8 ) func3=4; // LBU - if( _declaredType == TypeInteger.BOOL) func3=4; // LBU - if( _declaredType == TypeInteger.U16 ) func3=5; // LHU - if( _declaredType == TypeInteger.U32 ) func3=6; // LWU - if( _declaredType instanceof TypeInteger ti ) { - if( -128 <= ti._min && ti._max < 128 ) func3 = 0; // LB - } - - // float - if( _declaredType == TypeFloat.F32) func3 = 2; // fLW fSW - if( _declaredType == TypeFloat.F64) func3 = 3; // fLD fSD - - if( _declaredType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) - if( func3 == -1 ) throw Utils.TODO(); - return func3; - } + abstract int func3(); // Register mask allowed on input i. @Override public RegMask regmap(int i) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java index 965a3c7c..40d0359c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java @@ -41,8 +41,9 @@ public class NewRISC extends NewNode implements MachNode, RIPRelSize { // General form: "alloc #bytes PC" @Override public void asm(CodeGen code, SB sb) { - sb.p("ldi a1=#1\n"); + sb.p("\n"); // Multi-op trigger + sb.p("ldi ").p(code._mach.regs()[_arg2Reg]).p(" = #1\n"); sb.p("auipc a2=#calloc\n"); - sb.p("call a2+#calloc, a0"); + sb.p("call a2+#calloc"); } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java index 8a16f6b7..d455337b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java @@ -9,7 +9,7 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class SplitRISC extends SplitNode { - SplitRISC( String kind, byte round ) { super(kind,round, new Node[2]); } + SplitRISC( LRG lrg, String kind, byte round ) { super(lrg, kind,round, new Node[2]); } @Override public RegMask regmap(int i) { return riscv.SPLIT_MASK; } @Override public RegMask outregmap() { return riscv.SPLIT_MASK; } @Override public void encoding( Encoding enc ) { @@ -25,7 +25,7 @@ public class SplitRISC extends SplitNode { if( src >= riscv.MAX_REG ) { throw Utils.TODO(); // Very rare stack-stack move } - int off = enc._fun.computeStackOffset(enc._code,dst); + int off = fun(enc).computeStackOffset(enc._code,dst); int op = srcX ? RiscV.OP_STOREFP : RiscV.OP_STORE; if( srcX ) src -= riscv.F_OFFSET; enc.add4(RiscV.s_type(op, 0b011, riscv.RSP, src, off)); @@ -33,7 +33,7 @@ public class SplitRISC extends SplitNode { } if( src >= riscv.MAX_REG ) { // Load from SP - int off = enc._fun.computeStackOffset(enc._code,src); + int off = fun(enc).computeStackOffset(enc._code,src); int op = dstX ? RiscV.OP_LOADFP : RiscV.OP_LOAD; if( dstX ) dst -= riscv.F_OFFSET; enc.add4(RiscV.i_type(op, dst, 0b011, riscv.RSP, off)); @@ -58,10 +58,4 @@ public class SplitRISC extends SplitNode { enc.add4(RiscV.r_type(RiscV.OP_FP, dst, 0, src - riscv.F_OFFSET, 0, 0b1110001)); } } - - // General form: "mov dst = src" - @Override public void asm(CodeGen code, SB sb) { - FunNode fun = code._encoding==null ? null : code._encoding._fun; - sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); - } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java index 48cb7c78..c3fcf4d3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java @@ -4,6 +4,7 @@ import com.seaofnodes.isa.RiscV; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; @@ -27,7 +28,7 @@ public class StoreRISC extends MemOpRISC { if( i==1 ) return null; // mem if( i==2 ) return riscv.RMASK; // ptr // 2 - index - if( i==4 ) return _sz >= '4' + if( i==4 ) return _bytes >= 4 ? riscv.MEM_MASK // Word/dword value in GPR or FPR : riscv.RMASK; // Byte/short stores require a GPR return null; // Anti-dependence @@ -42,6 +43,11 @@ public class StoreRISC extends MemOpRISC { enc.add4(RiscV.s_type(op, func3()&7, ptr, val == -1 ? riscv.ZERO : val, _off)); } + // func3 is based on load/store size and extend + @Override int func3() { + return Integer.numberOfTrailingZeros(_bytes); + } + @Override public void asm(CodeGen code, SB sb) { asm_address(code,sb).p(","); if( val()==null ) sb.p("#").p("0"); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index e57f6e09..44ef1a95 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -2,25 +2,27 @@ package com.seaofnodes.simple.node.cpus.riscv; import com.seaofnodes.isa.RiscV; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.MachNode; -import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; -public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { - TFPRISC(ConstantNode con) { super(con); } +public class TFPRISC extends FunPtrNode implements MachNode, RIPRelSize { + final String _ext; + // Pointer to a Simple function + TFPRISC( FunPtrNode fptr ) { super(fptr); _ext = null; } + // Pointer to an Extern "C" function + TFPRISC( TypeFunPtr fptr, String ext ) { super(fptr,CodeGen.CODE._start,null); _type = fptr; _ext = ext; } @Override public String op() { return "ldx"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public TFPRISC copy() { return new TFPRISC(this); } + @Override public TFPRISC copy() { return new TFPRISC((TypeFunPtr)_con,_ext); } @Override public void encoding( Encoding enc ) { - enc.relo(this); + if( _ext==null ) enc.relo(this); // Internal patch + else enc.external(this,_ext); // ELF-file external patch // TODO: 1 op encoding, plus a TODO if it does not fit short dst = enc.reg(this); - TypeFunPtr tfp = (TypeFunPtr)_con; // auipc t0,0 enc.add4(RiscV.u_type(RiscV.OP_AUIPC, dst, 0)); // addi t1,t0 + #0 @@ -33,9 +35,14 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); if( opLen==8 ) { - // ADDI sign-extends its low 12 bits, so round the AUIPC high part. - enc.patch4(opStart ,RiscV.u_type(RiscV.OP_AUIPC, rpc, (delta+0x800)>>12)); - enc.patch4(opStart+4,RiscV.i_type(RiscV.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); + int hi20 = (delta + 0x800) >> 12; + int lo12 = delta - (hi20 << 12); + // AUIPC (upper 20 bits) + // opstart of add + enc.patch4(opStart ,RiscV.u_type(RiscV.OP_AUIPC, rpc, hi20)); + // addi(low 12 bits) + enc.patch4(opStart+4,RiscV.i_type(RiscV.OP_IMM, rpc, 0, rpc, lo12 & 0xFFF)); + // addi } else { // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); @@ -43,7 +50,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { } @Override public void asm(CodeGen code, SB sb) { - _con.print(sb.p(code.reg(this)).p(" #")); + _type.print(sb.p(code.reg(this)).p(" #")); } @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java index 7bc2db7e..a5ff3753 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java @@ -9,14 +9,16 @@ import com.seaofnodes.simple.type.TypeMemPtr; import com.seaofnodes.simple.util.SB; public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { - TMPRISC(ConstantNode con) { super(con); } + final String _ext; + TMPRISC( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ldp"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } @Override public boolean isClone() { return true; } - @Override public TMPRISC copy() { return new TMPRISC(this); } + @Override public TMPRISC copy() { return new TMPRISC(this,_ext); } @Override public void encoding( Encoding enc ) { - enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + if( _ext!=null ) enc.externalData(this,_ext); + else enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); short dst = enc.reg(this); // AUIPC dst,#hi20_constant_pool enc.add4(RiscV.u_type(RiscV.OP_AUIPC, dst, 0)); @@ -29,9 +31,9 @@ public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short dst = enc.reg(this); - // Round the high part because ADDI's low 12 bits are signed. + // AUIPC dst,#hi20_constant_pool enc.patch4(opStart , RiscV.u_type(RiscV.OP_AUIPC, dst, (delta+0x800)>>12)); - // ADDI dst,dst,#low12_constant_pool + // ADDI's low 12 bits are signed; round the AUIPC page accordingly. enc.patch4(opStart+4, RiscV.i_type(RiscV.OP_IMM, dst, 0, dst, delta & 0xFFF)); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java index 7c994624..19b91866 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java @@ -15,7 +15,6 @@ public class riscv extends Machine { } @Override public String name() {return "riscv";} - //@Override public int maxReg() { return MAX_REG; } // Using ABI names instead of register names public static int ZERO = 0, RPC= 1, RSP= 2, S12= 3, S13= 4, T0 = 5, T1 = 6, T2 = 7; @@ -34,24 +33,24 @@ public class riscv extends Machine { public static final int F_OFFSET = 32; static final String[] REGS = new String[] { - "zero","rpc" , "rsp" , "s12" , "s13" , "t0" , "t1" , "t2" , - "s0" , "s1" , "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , - "a6" , "a7" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" , - "s8" , "s9" , "s10" , "s11" , "t3" , "t4" , "t5" , "t6" , - "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , - "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , - "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , - "fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11" - // Register-based naming hella easier to debug than "official" register - // names when single-stepping in debugger. - //"zero", "r1" , "rsp" , "r3" , "r4" , "r5" , "r6" , "r7" , - //"r8" , "r9" , "r10" , "r11", "r12", "r13", "r14", "r15", - //"r16" , "r17" , "r18" , "r19", "r20", "r21", "r22", "r23", - //"r24" , "r25" , "r26" , "r27", "r28", "r29", "r30", "r31", + //"zero","rpc" , "rsp" , "s12" , "s13" , "t0" , "t1" , "t2" , + //"s0" , "s1" , "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , + //"a6" , "a7" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" , + //"s8" , "s9" , "s10" , "s11" , "t3" , "t4" , "t5" , "t6" , //"f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , //"fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , //"fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , //"fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11" + // Register-based naming hella easier to debug than "official" register + // names when single-stepping in debugger. + "zero", "r1" , "rsp" , "r3" , "r4" , "r5" , "r6" , "r7" , + "r8" , "r9" , "r10" , "r11", "r12", "r13", "r14", "r15", + "r16" , "r17" , "r18" , "r19", "r20", "r21", "r22", "r23", + "r24" , "r25" , "r26" , "r27", "r28", "r29", "r30", "r31", + "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , + "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , + "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , + "fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11" }; @Override public String[] regs() { return REGS; } @@ -92,7 +91,7 @@ public class riscv extends Machine { public static RegMask FA6_MASK = new RegMask(FA6); public static RegMask FA7_MASK = new RegMask(FA7); - // Int arguments calling conv + // Int/ptr arguments calling convention static RegMask[] CALLINMASK = new RegMask[] { A0_MASK, A1_MASK, @@ -138,10 +137,16 @@ public class riscv extends Machine { if( idx==0 ) return RPC_MASK; if( idx==1 ) return null; if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + boolean hidden = hiddenSelf(tfp); + int sigidx = idx-2; + if( hidden ) { + if( sigidx==0 ) return null; + sigidx--; + } // Count floats in signature up to index int fcnt=0; - for( int i=2; i<idx; i++ ) - if( tfp.arg(i-2) instanceof TypeFloat ) + for( int i=hidden ? 1 : 0; i<idx-2; i++ ) + if( tfp.arg(i) instanceof TypeFloat ) fcnt++; // Floats up to XMMS in XMM registers if( tfp.arg(idx-2) instanceof TypeFloat ) { @@ -149,23 +154,26 @@ public class riscv extends Machine { return XMMS[fcnt]; } else { RegMask[] cargs = CALLINMASK; - if( idx-2-fcnt < cargs.length ) - return cargs[idx-2-fcnt]; + if( sigidx-fcnt < cargs.length ) + return cargs[sigidx-fcnt]; } // Pass on stack slot(8 and higher) if( maxArgSlot>0 ) throw Utils.TODO(); - return new RegMask(MAX_REG + 1 + (idx - 2)); + return new RegMask(MAX_REG + 1 + sigidx); } @Override public short maxArgSlot( TypeFunPtr tfp ) { int icnt=0, fcnt=0; // Count of ints, floats - for( int i=0; i<tfp.nargs(); i++ ) { + for( int i=hiddenSelf(tfp) ? 1 : 0; i<tfp.nargs(); i++ ) { if( tfp.arg(i) instanceof TypeFloat ) fcnt++; else icnt++; } int nstk = Math.max(icnt-8,0)+Math.max(fcnt-8,0); return (short)nstk; } + private static boolean hiddenSelf(TypeFunPtr tfp) { + return tfp.nargs() > 0 && tfp.arg(0) == TypePtr.PTR; + } static final long CALLER_SAVE = (1L<<RPC) | @@ -186,7 +194,7 @@ public class riscv extends Machine { @Override public CFGNode jump() { return new UJmpRISC(); } // Create a split op; any register to any register, including stack slots - @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitRISC(kind,round); } + @Override public SplitNode split(LRG lrg, String kind, byte round ) { return new SplitRISC(lrg, kind,round); } // True if signed 12-bit immediate public static boolean imm12(TypeInteger ti) { @@ -203,30 +211,33 @@ public class riscv extends Machine { @Override public Node instSelect( Node n ) { return switch (n) { - case AddFNode addf -> addf(addf); case AddNode add -> add(add); case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CallNode call -> call(call); - case CastNode cast -> new CastMach(cast); + case PtrToIntNode ptr -> new PtrToIntMach(ptr); + case GuardNode guard -> new GuardMach(guard); case CallEndNode cend -> new CallEndMach(cend); case CProjNode c -> new CProjNode(c); case ConstantNode con -> con(con); - case DivFNode divf -> new DivFRISC(divf); - case DivNode div -> new DivRISC(div); + case DivNode div -> div.mode()==2 ? new DivFRISC(div) : new DivRISC(div); + case EscapeNode esc -> new EscapeNode(esc); case FunNode fun -> new FunRISC(fun); + case FunPtrNode fptr -> fptr(fptr); case IfNode iff -> jmp(iff); case LoadNode ld -> ld(ld); case MemMergeNode mem -> new MemMergeNode(mem); - case MinusNode neg -> new NegRISC(neg); - case MulFNode mulf -> new MulFRISC(mulf); - case MulNode mul -> new MulRISC(mul); + case MinusNode neg -> { + if( neg.mode()==2 ) throw Utils.TODO(); + yield new NegRISC(neg); + } + case MulNode mul -> mul.mode()==2 ? new MulFRISC(mul) : new MulRISC(mul); case NewNode nnn -> nnn(nnn); case NotNode not -> new NotRISC(not); case OrNode or -> or(or); case ParmNode parm -> new ParmRISC(parm); - case BulkMemPhiNode phi -> new BulkMemPhiNode(phi); - case MemPhiNode phi -> new MemPhiNode(phi); + case BulkMemPhiNode phi-> new BulkMemPhiNode(phi); + case MemPhiNode phi -> new MemPhiNode(phi); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); case ReadOnlyNode read-> new ReadOnlyMach(read); @@ -234,11 +245,12 @@ public class riscv extends Machine { case SarNode sar -> sra(sar); case ShlNode shl -> sll(shl); case ShrNode shr -> srl(shr); + case StartCUNode start -> new StartCUNode(start); + case StopCUNode stop -> new StopCUNode(stop); case StartNode start -> new StartNode(start); case StopNode stop -> new StopNode(stop); case StoreNode st -> st(st); - case SubFNode subf -> new SubFRISC(subf); - case SubNode sub -> sub(sub); + case SubNode sub -> sub.mode()==2 ? new SubFRISC(sub) : sub(sub); case ToFloatNode tfn -> i2f8(tfn); case ToIntegerNode cvt -> new F8ToIRISC(cvt); case XorNode xor -> xor(xor); @@ -249,11 +261,9 @@ public class riscv extends Machine { }; } - private Node addf(AddFNode addf) { - return new AddFRISC(addf); - } - private Node add(AddNode add) { + if( add.mode()==2 ) + return new AddFRISC(add); if( add.in(2) instanceof ConstantNode off2 && off2._con instanceof TypeInteger ti && imm12(ti) ) return new AddIRISC(add, (int)ti.value(),true); return new AddRISC(add); @@ -271,8 +281,10 @@ public class riscv extends Machine { } private Node call(CallNode call) { - return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp - ? new CallRISC(call, tfp) + return call.fptr() instanceof FunPtrNode fptr + ? new CallRISC(call, (TypeFunPtr)fptr._type) + : call.fptr() instanceof ConstantNode con + ? new CallRISC(call, (TypeFunPtr)con._type) : new CallRRISC(call); } private Node nnn(NewNode nnn) { @@ -311,9 +323,13 @@ public class riscv extends Machine { } private Node con( ConstantNode con ) { - if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs + if( !con._con.isConstant() ) + return ConstantNode.raw(con); // Default unknown caller inputs + String ext = con instanceof ExternNode ext0 ? ext0._extern : null; return switch( con._con ) { case TypeInteger ti -> { + // External; without knowing the size assume we have to load something + if( ext!=null ) yield new Int8RISC(con,ext); if( imm12(ti) ) yield new IntRISC(con); long x = ti.value(); if( imm20Exact(ti) ) yield new LUI((int)x); @@ -326,18 +342,22 @@ public class riscv extends Machine { } // Need more complex sequence for larger constants... or a load // from a constant pool, which does not need an extra register - yield new Int8RISC(con); + yield new Int8RISC(con,null); } // Load from constant pool - case TypeFloat tf -> new FltRISC(con); - case TypeFunPtr tfp -> new TFPRISC(con); - case TypeMemPtr tmp -> new TMPRISC(con); + case TypeFloat tf -> new FltRISC(con,ext); + case TypeMemPtr tmp -> new TMPRISC(con,ext); + case TypeFunPtr tfp -> new TFPRISC(tfp,ext); case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case Type t -> t==Type.NIL ? new IntRISC(con) : new ConstantNode(con); + case Type t -> t==Type.NIL ? new IntRISC(con) : ConstantNode.raw(con); }; } + private Node fptr( FunPtrNode con ) { + return new TFPRISC(con); + } + private Node jmp( IfNode iff ) { if( iff.in(1) instanceof BoolNode bool && !bool.isFloat() ) { // if less than or equal switch inputs @@ -394,7 +414,7 @@ public class riscv extends Machine { private Node prj(ProjNode prj) { TypeInteger ret = cReturn(prj); if( ret!=null ) return new ExtendRISC(prj,ret); - return new ProjRISC(prj); + return prj.in(0) instanceof StartNode ? new ProjNode(prj) : new ProjRISC(prj); } private Node ld(LoadNode ld) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java index 974f690f..74af9266 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java @@ -7,7 +7,7 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class AddFMemX86 extends MemOpX86 { - AddFMemX86( AddFNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) { + AddFMemX86( AddNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) { super(add,ld, base, idx, off, scale, 0, val ); } @Override public String op() { return "addf"+_sz; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java index d1a43b83..6bafbf37 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java @@ -9,21 +9,27 @@ import com.seaofnodes.simple.util.SB; public class CallX86 extends CallNode implements MachNode, RIPRelSize { final TypeFunPtr _tfp; final String _name; + final boolean _extern; CallX86( CallNode call, TypeFunPtr tfp ) { super(call); _inputs.pop(); // Pop constant target assert tfp.isConstant(); _tfp = tfp; - FunNode fun = CodeGen.CODE.link(tfp); - _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + _name = CodeGen.CODE.funcName(tfp.fidx()); + _extern = CodeGen.CODE.externFunc(tfp.fidx()) != null; } @Override public String op() { return "call"; } @Override public String label() { return op(); } @Override public String name() { return _name; } @Override public TypeFunPtr tfp() { return _tfp; } - @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask regmap(int i) { + return _extern + ? x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot,CodeGen.CODE._cCallingConv) + : x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot); + } @Override public RegMask outregmap() { return null; } @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr + @Override public boolean external() { return _extern; } @Override public void encoding( Encoding enc ) { FunNode fun = CodeGen.CODE.link(_tfp); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java index 7b7d98d5..4014045b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java @@ -20,8 +20,8 @@ public class CmpMemX86 extends MemOpX86 { short ptr=enc.reg(ptr()), idx=enc.reg(idx()), src=enc.reg(val()); if( src==-1 ) { assert !_swap; - X86.cmpImm(enc,_declaredType.log_size(),_imm,ptr,idx,_off,_scale); - } else encVal(enc,_declaredType,ptr,idx,src,_off,_scale,_swap); + X86.cmpImm(enc,_con.log_size(),_imm,ptr,idx,_off,_scale); + } else encVal(enc,_con,ptr,idx,src,_off,_scale,_swap); } static void encVal(Encoding enc, Type decl, short ptr, short idx, short src, int off, int scale, boolean _swap) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java index da9bdce7..59f06341 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java @@ -4,17 +4,20 @@ import com.seaofnodes.isa.X86; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class FltX86 extends ConstantNode implements MachNode, RIPRelSize{ private byte _encSize; - FltX86(ConstantNode con ) { super(con); } + final String _ext; + FltX86( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ld8"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return x86_64_v2.XMASK; } @Override public boolean isClone() { return true; } - @Override public Node copy() { return new FltX86(this); } + @Override public Node copy() { return new FltX86(this,_ext); } @Override public void encoding( Encoding enc ) { + if( _ext!=null ) throw Utils.TODO(); _encSize=X86.rip(enc,0xF2,0x0F10,false,enc.reg(this)-x86_64_v2.XMM_OFFSET); enc.largeConstant(this,_con,_encSize-4,2/*ELF PC32*/); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java index c7a20e4d..0e44aee7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java @@ -11,6 +11,7 @@ public class FunX86 extends FunNode implements MachNode { FunX86( FunNode fun ) { super(fun); } @Override public void postSelect(CodeGen code) { super.postSelect(code); + _maxArgSlot = code._mach.maxArgSlot(sig(),code._callingConv); // One more for RPC pre-pushed; X86 special _maxArgSlot++; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java index 656b1543..2ffaa3d1 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java @@ -6,15 +6,17 @@ import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Integer constants public class IntX86 extends ConstantNode implements MachNode { - IntX86( ConstantNode con ) { super(con); } + final String _ext; + IntX86( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return _con == Type.NIL || _con == TypeInteger.ZERO ? "xor" : "ldi"; } @Override public boolean isClone() { return true; } - @Override public Node copy() { return new IntX86(this); } + @Override public Node copy() { return new IntX86(this,_ext); } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } // Zero-set uses XOR kills flags @@ -23,6 +25,7 @@ public class IntX86 extends ConstantNode implements MachNode { } @Override public void encoding( Encoding enc ) { + if( _ext!=null ) throw Utils.TODO(); X86.constant(enc,enc.reg(this),_con==Type.NIL ? 0 : ((TypeInteger)_con).value()); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java index d4f1413e..5c472dbe 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java @@ -13,7 +13,7 @@ public class LoadX86 extends MemOpX86 { super(ld,ld, base, idx, off, scale, 0); } @Override public String op() { return "ld"+_sz; } - @Override public RegMask outregmap() { return x86_64_v2.MEM_MASK; } + @Override public RegMask outregmap() { return _con instanceof TypeFloat ? x86_64_v2.XMASK : x86_64_v2.WMASK; } @Override public void encoding( Encoding enc ) { // REX.W + 8B /r MOV r64, r/m64 // Zero extension for u8, u16 and u32 but sign extension i8, i16, i32 @@ -21,7 +21,7 @@ public class LoadX86 extends MemOpX86 { short dst = enc.reg(this ); short ptr = enc.reg(ptr()); short idx = enc.reg(idx()); - enc(enc, _declaredType, dst, ptr, idx, _off, _scale); + enc(enc, _con, dst, ptr, idx, _off, _scale); } static void enc( Encoding enc, Type decl, short dst, short ptr, short idx, int off, int scale ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java index 309e62d9..fcca7f8f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java @@ -6,7 +6,6 @@ import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.util.SB; -import com.seaofnodes.simple.util.Utils; import java.lang.StringBuilder; // Generic X86 memory operand base. @@ -42,7 +41,8 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode { _off = off; _scale = scale; _imm = imm; - _sz = (char)('0'+(1<<_declaredType.log_size())); + int size = mop instanceof StoreNode st ? st.storeSize() : 1<<_con.log_size(); + _sz = (char)('0'+size); } // Store-based flavors have a value edge @@ -59,8 +59,8 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode { } @Override public String label() { return op(); } - @Override public Type compute() { throw Utils.TODO(); } - @Override public Node idealize() { throw Utils.TODO(); } + @Override public Type compute() { throw new AssertionError("Do not call compute on "+getClass().getSimpleName()); } + @Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); } // Register mask allowed on input i. @Override public RegMask regmap(int i) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java index 1cfc1c42..d6a06c2f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java @@ -16,7 +16,8 @@ public class NewX86 extends NewNode implements MachNode { } // General form: "alloc #bytes PC" @Override public void asm(CodeGen code, SB sb) { - sb.p("ldi rcx = #1\n"); + sb.p("\n"); // Multi-op trigger + sb.p("ldi ").p(code._mach.regs()[_arg2Reg]).p(" = #1\n"); sb.p("call #calloc"); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java index e8281975..b2b643d3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java @@ -12,8 +12,7 @@ import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.util.Utils; public class SplitX86 extends SplitNode { - SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); } - @Override public String op() { return "mov"; } + SplitX86( LRG lrg, String kind, byte round ) { super(lrg,kind,round, new Node[2]); } @Override public RegMask regmap(int i) { return x86_64_v2.SPLIT_MASK; } @Override public RegMask outregmap() { return x86_64_v2.SPLIT_MASK; } @@ -26,10 +25,10 @@ public class SplitX86 extends SplitNode { boolean dstX=dst>=x86_64_v2.XMM_OFFSET, srcX=src>=x86_64_v2.XMM_OFFSET; // Stack spills if( dst >= x86_64_v2.MAX_REG ) { - int off = enc._fun.computeStackOffset(enc._code,dst); + int off = fun(enc).computeStackOffset(enc._code,dst); if( src >= x86_64_v2.MAX_REG ) { // Rare stack-stack move. push [RSP+soff]; pop [RSP+doff] - int soff = enc._fun.computeStackOffset(enc._code,src); + int soff = fun(enc).computeStackOffset(enc._code,src); X86.stackCopy(enc,soff,off); return; } @@ -37,7 +36,7 @@ public class SplitX86 extends SplitNode { return; } if( src >= x86_64_v2.MAX_REG ) { - int off = enc._fun.computeStackOffset(enc._code,src); + int off = fun(enc).computeStackOffset(enc._code,src); LoadX86.enc(enc, dstX ? TypeFloat.F64 : TypeInteger.BOT, dst, (short)x86_64_v2.RSP, (short)-1, off, 0); return; } @@ -45,10 +44,4 @@ public class SplitX86 extends SplitNode { X86.move(enc,dstX,srcX,dstX ? dst-x86_64_v2.XMM_OFFSET : dst, srcX ? src-x86_64_v2.XMM_OFFSET : src); } - - // General form: "mov dst = src" - @Override public void asm(CodeGen code, SB sb) { - FunNode fun = code._encoding==null ? null : code._encoding._fun; - sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); - } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java index c83dfd44..9ffa25fc 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -27,8 +27,8 @@ public class StoreX86 extends MemOpX86 { @Override public RegMask outregmap() { return null; } @Override public void encoding( Encoding enc ) { short ptr=enc.reg(ptr()), idx=enc.reg(idx()), src=enc.reg(val()); - if( src==-1 ) X86.storeImm(enc,_declaredType.log_size(),_imm,ptr,idx,_off,_scale); - else encVal(enc,_declaredType,ptr,idx,src,_off,_scale); + if( src==-1 ) X86.storeImm(enc,Integer.numberOfTrailingZeros(_sz-'0'),_imm,ptr,idx,_off,_scale); + else encVal(enc,_con,ptr,idx,src,_off,_scale); } // Non-immediate encoding diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java index fff2fb04..e3563713 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java @@ -3,39 +3,39 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; import com.seaofnodes.isa.X86; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; -import com.seaofnodes.simple.node.cpus.riscv.riscv; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Function constants -public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { - TFPX86( ConstantNode con ) { super(con); } - @Override public String op() { - return _con == Type.NIL ? "xor" : "ldx"; - } +public class TFPX86 extends FunPtrNode implements MachNode, RIPRelSize { + private byte _opLen; + final String _ext; // External name + // Pointer to a Simple function + TFPX86( FunPtrNode fptr ) { this((TypeFunPtr)fptr._type,null); } + // Spill clone: copy inputs without registering their reverse edges; + // insertBefore will place and register the clone in its use block. + private TFPX86( TFPX86 fptr ) { super(fptr); _ext = fptr._ext; } + // Pointer to an Extern "C" function + TFPX86( TypeFunPtr fptr, String ext ) { super(fptr,CodeGen.CODE._start,null); _type = fptr; _ext = ext; } + @Override public String op() { return "ldx"; } + @Override public String label() { return op(); } @Override public boolean isClone() { return true; } - @Override public Node copy() { return new TFPX86(this); } + @Override public TFPX86 copy() { return new TFPX86(this); } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } - // Zero-set uses XOR kills flags - @Override public RegMask killmap() { - return _con == Type.NIL ? x86_64_v2.FLAGS_MASK : null; - } - @Override public void encoding( Encoding enc ) { - if( _con==Type.NIL ) { X86.constant(enc,enc.reg(this),0); return; } - enc.relo(this); - X86.rip(enc,0,0x8D,true,enc.reg(this)); + if( _ext==null ) enc.relo(this); + else enc.external(this,_ext); + _opLen=X86.rip(enc,0,0x8D,true,enc.reg(this)); } - @Override public byte encSize(int delta) { - return 7; - } + @Override public byte encSize(int delta) { return _opLen; } - // Delta is from opcode start + // Delta is from opcode start, X86 expects it from opcode end @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { - enc.patch4(opStart + 3, delta - 7); + enc.patch4(opStart + opLen - 4, delta - opLen); } // Human-readable form appended to the SB. Things like the encoding, @@ -43,11 +43,9 @@ public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { // Just something like "ld4\tR17=[R18+12] // Load array base". // General form: "op\tdst=src+src" @Override public void asm(CodeGen code, SB sb) { - String reg = code.reg(this); - if( _con == Type.NIL ) - sb.p(reg).p(",").p(reg); - else - _con.print(sb.p(reg).p(" = #")); + sb.p(code.reg(this)); + if( _ext == null ) _type.print(sb.p(" #")); + else sb.p(_ext); } @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java index c78ac6de..682597f4 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java @@ -7,30 +7,29 @@ import com.seaofnodes.simple.type.TypeMemPtr; import com.seaofnodes.simple.util.SB; public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ - TMPX86(ConstantNode con ) { super(con); } + private byte _opLen; + final String _ext; + TMPX86( ConstantNode con, String ext ) { super(con); _ext = ext; } @Override public String op() { return "ldp"; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } @Override public boolean isClone() { return true; } - @Override public Node copy() { return new TMPX86(this); } + @Override public Node copy() { return new TMPX86(this,_ext); } @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); - X86.rexF(dst, 0, 0, true, enc); - enc.add1(0x8D).add1(X86.modrm(X86.MOD.INDIRECT, dst, 0b101)).add4(0); - int opLen = 1/*rexF*/+1/*opcode 0x8D*/+1/*modrm*/+4/*pc rel offset*/; - // Base of constant array - TypeMemPtr tmp = (TypeMemPtr)_con; - int baseOff = tmp._obj.aryBase(); - enc.largeConstant(this,tmp._obj,opLen-baseOff,2/*ELF encoding PC32*/); + // 0 or 1 for REX depending on the dst. + _opLen = X86.rip(enc,0,0x8D,true,dst); + if( _ext!=null ) enc.externalData(this,_ext); + else enc.largeConstant(this,((TypeMemPtr)_con)._obj, _opLen-4, 2/*ELF encoding PC32*/); } // Delta is from opcode start - @Override public byte encSize(int delta) { return (byte)7; } + @Override public byte encSize(int delta) { return _opLen; } // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { - enc.patch4(opStart+opLen-4,delta-opLen); + enc.patch4(opStart + opLen - 4, delta - opLen); } @Override public void asm(CodeGen code, SB sb) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java index e283bc8f..ff15fdad 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -97,22 +97,29 @@ public class x86_64_v2 extends Machine { // Map from function signature and argument index to register. // Used to set input registers to CallNodes, and ParmNode outputs. @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot, String conv ) { return callInMask(tfp,idx,maxArgSlot,conv); } static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { + return callInMask(tfp,idx,maxArgSlot,CodeGen.CODE._callingConv); + } + static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot, String conv ) { if( idx==0 ) return RPC_MASK; if( idx==1 ) return null; if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence - return switch( CodeGen.CODE._callingConv ) { + return switch( conv ) { case "SystemV" -> callSys5 (tfp,idx,maxArgSlot); - case "Win64" -> callWin64(tfp,idx,maxArgSlot); + case "win64" -> callWin64(tfp,idx,maxArgSlot); default -> throw Utils.TODO(); }; } // Maximum stack args used by this signature @Override public short maxArgSlot( TypeFunPtr tfp ) { - return switch( CodeGen.CODE._callingConv ) { + return maxArgSlot(tfp,CodeGen.CODE._callingConv); + } + @Override public short maxArgSlot( TypeFunPtr tfp, String conv ) { + return switch( conv ) { case "SystemV" -> maxArgSlotSys5 (tfp); - case "Win64" -> maxArgSlotWin64(tfp); + case "win64" -> maxArgSlotWin64(tfp); default -> throw Utils.TODO(); }; } @@ -145,14 +152,22 @@ public class x86_64_v2 extends Machine { static RegMask callWin64(TypeFunPtr tfp, int idx, int maxArgSlot ) { // 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+maxArgSlot+(idx-2)); + int sigidx = idx-2; + if( hiddenSelf(tfp) ) { + if( sigidx==0 ) return null; + sigidx--; + } + if( sigidx >= 4 ) + return new RegMask(MAX_REG+maxArgSlot+sigidx); return tfp.arg(idx-2) instanceof TypeFloat - ? XMMS8 [idx-2] - : WIN64_CALL[idx-2]; + ? XMMS8 [sigidx] + : WIN64_CALL[sigidx]; } static short maxArgSlotWin64(TypeFunPtr tfp) { - return (short)tfp.nargs(); + return (short)Math.max(4,tfp.nargs() - (hiddenSelf(tfp) ? 1 : 0)); + } + static short maxIncomingArgSlotWin64(TypeFunPtr tfp) { + return (short)Math.max(0,tfp.nargs() - (hiddenSelf(tfp) ? 1 : 0) - 4); } // Sys5: max 6 GPRs and 8 FPRS filled first. Extra args land in increasing @@ -186,9 +201,14 @@ public class x86_64_v2 extends Machine { static RegMask callSys5(TypeFunPtr tfp, int idx, int maxArgSlot ) { // First 6 integers passed in registers: rdi,rsi,rdx,rcx,r08,r09 // First 8 floats passed in registers: xmm0-xmm7 + int sigidx = idx-2; + if( hiddenSelf(tfp) ) { + if( sigidx==0 ) return null; + sigidx--; + } int icnt=0, fcnt=0; // Count of ints, floats - for( int i=2; i<idx; i++ ) { - if( tfp.arg(i-2) instanceof TypeFloat ) fcnt++; + for( int i=hiddenSelf(tfp) ? 1 : 0; i<idx-2; i++ ) { + if( tfp.arg(i) instanceof TypeFloat ) fcnt++; else icnt++; } int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); @@ -198,13 +218,16 @@ public class x86_64_v2 extends Machine { } static short maxArgSlotSys5(TypeFunPtr tfp) { int icnt=0, fcnt=0; // Count of ints, floats - for( int i=0; i<tfp.nargs(); i++ ) { + for( int i=hiddenSelf(tfp) ? 1 : 0; i<tfp.nargs(); i++ ) { if( tfp.arg(i) instanceof TypeFloat ) fcnt++; else icnt++; } int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); return (short)nstk; } + private static boolean hiddenSelf(TypeFunPtr tfp) { + return tfp.nargs() > 0 && tfp.arg(0) == TypePtr.PTR; + } static final long SYSTEM5_CALLER_SAVE = (1L << RAX) | (1L << RCX) | (1L << RDX) | @@ -223,12 +246,18 @@ public class x86_64_v2 extends Machine { (1L<<XMM4) | (1L<<XMM5) ; @Override public long callerSave() { - return switch (CodeGen.CODE._callingConv) { + return callerSave(CodeGen.CODE._callingConv); + } + @Override public long callerSave(String conv) { + return switch (conv) { case "SystemV" -> SYSTEM5_CALLER_SAVE; - case "Win64" -> WIN64_CALLER_SAVE; - default -> throw new IllegalArgumentException("Unknown calling convention: " + CodeGen.CODE._callingConv); + case "win64" -> WIN64_CALLER_SAVE; + default -> throw new IllegalArgumentException("Unknown calling convention: " + conv); }; } + @Override public String cCallingConv(String callingConv) { + return callingConv; + } @Override public long neverSave() { return 1L<<RSP; } @Override public RegMask retMask( TypeFunPtr tfp ) { return tfp.ret() instanceof TypeFloat ? XMM0_MASK : RAX_MASK; @@ -237,8 +266,8 @@ public class x86_64_v2 extends Machine { // Create a split op; any register to any register, including stack slots - @Override public SplitNode split(String kind, byte round, LRG lrg) { - return new SplitX86(kind, round); + @Override public SplitNode split(LRG lrg, String kind, byte round ) { + return new SplitX86(lrg,kind, round); } // Return a MachNode unconditional branch @@ -250,30 +279,33 @@ public class x86_64_v2 extends Machine { @Override public Node instSelect(Node n) { return switch (n) { - case AddFNode addf -> addf(addf); case AddNode add -> add(add); case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CProjNode c -> new CProjNode(c); case CallEndNode cend -> new CallEndMach(cend); case CallNode call -> call(call); - case CastNode cast -> new CastMach(cast); + case PtrToIntNode ptr -> new PtrToIntMach(ptr); + case GuardNode guard -> new GuardMach(guard); case ConstantNode con -> con(con); - case DivFNode divf -> new DivFX86(divf); - case DivNode div -> new DivX86(div); + case DivNode div -> div.mode()==2 ? new DivFX86(div) : new DivX86(div); + case EscapeNode esc -> new EscapeNode(esc); case FunNode fun -> new FunX86(fun); + case FunPtrNode fptr -> fptr(fptr); case IfNode iff -> jmp(iff); case LoadNode ld -> ld(ld); case MemMergeNode mem -> new MemMergeNode(mem); - case MinusNode neg -> new NegX86(neg); - case MulFNode mulf -> new MulFX86(mulf); - case MulNode mul -> mul(mul); + case MinusNode neg -> { + if( neg.mode()==2 ) throw Utils.TODO(); + yield new NegX86(neg); + } + case MulNode mul -> mul.mode()==2 ? new MulFX86(mul) : mul(mul); case NewNode nnn -> new NewX86(nnn); case NotNode not -> new NotX86(not); case OrNode or -> or(or); case ParmNode parm -> new ParmX86(parm); - case BulkMemPhiNode phi -> new BulkMemPhiNode(phi); - case MemPhiNode phi -> new MemPhiNode(phi); + case BulkMemPhiNode phi-> new BulkMemPhiNode(phi); + case MemPhiNode phi -> new MemPhiNode(phi); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); case ReadOnlyNode read-> new ReadOnlyMach(read); @@ -281,14 +313,15 @@ public class x86_64_v2 extends Machine { case SarNode sar -> sar(sar); case ShlNode shl -> shl(shl); case ShrNode shr -> shr(shr); + case StartCUNode start -> new StartCUNode(start); + case StopCUNode stop -> new StopCUNode(stop); case StartNode start -> new StartNode(start); case StopNode stop -> new StopNode(stop); case StoreNode st -> st(st); - case SubFNode subf -> new SubFX86(subf); - case SubNode sub -> sub(sub); + case SubNode sub -> sub.mode()==2 ? new SubFX86(sub) : sub(sub); case ToFloatNode tfn -> i2f8(tfn); case ToIntegerNode cvt -> new F8ToIX86(cvt); - case XCtrlNode x -> new ConstantNode(Type.XCONTROL); + case XCtrlNode x -> ConstantNode.raw(Type.XCONTROL); case XorNode xor -> xor(xor); case LoopNode loop -> new LoopNode(loop); @@ -303,14 +336,12 @@ public class x86_64_v2 extends Machine { // Attempt a full LEA-style break down. private Node add(AddNode add) { + if( add.mode()==2 ) + return new AddFX86(add); Node lhs = add.in(1); Node rhs = add.in(2); - if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && ld._declaredType.log_size() >= 3) + if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && ld.declaredType().log_size() >= 3) return new AddMemX86(add, address(ld), ld.ptr(), idx, off, scale, 0, rhs); - - if( rhs instanceof LoadNode ld && ld.nOuts()==1 && ld._declaredType.log_size()>=3 ) - return new AddMemX86(add,address(ld),ld.ptr(),idx,off,scale, 0,lhs); - // Attempt a full LEA-style break down. // Returns one of AddX86, AddIX86, LeaX86, or LHS if( rhs instanceof ConstantNode off2 && off2._con instanceof TypeInteger toff ) { @@ -333,17 +364,6 @@ public class x86_64_v2 extends Machine { } - private Node addf(AddFNode addf) { - if(addf.in(1) instanceof LoadNode ld && ld.nOuts() == 1) - return new AddFMemX86(addf, address(ld), ld.ptr(), idx, off, scale, addf.in(2)); - -// if(addf.in(2) instanceof LoadNode ld && ld.nOuts() == 1) -// throw Utils.TODO(); // Swap load sides - - return new AddFX86(addf); - } - - private Node _lea(Node add, Node base, Node idx, int off) { int scale = 0; if( base instanceof ShlNode && !(idx instanceof ShlNode) ) @@ -367,8 +387,10 @@ public class x86_64_v2 extends Machine { } private Node call(CallNode call) { - return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp - ? new CallX86(call, tfp) + return call.fptr() instanceof FunPtrNode con + ? new CallX86(call, (TypeFunPtr)con._type) + : call.fptr() instanceof ConstantNode con && con._type instanceof TypeFunPtr + ? new CallX86(call, (TypeFunPtr)con._type) : new CallRX86(call); } @@ -393,12 +415,13 @@ public class x86_64_v2 extends Machine { // Since cmp does not record a BOP, SetX/Jmp need to know if the CMP is swapped. // Vs memory - if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && rhs._type.isa(ld._declaredType) ) + if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && rhs._type.isa(ld.declaredType()) ) return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false); // Operands swap in the encoding directly, no need for Set/Jmp to swap `bop` - if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType) && - (val!=null || bool.op()=="==" || bool.op()=="!=") ) + if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld.declaredType()) && + (!(lhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value())) || + bool.op()=="==" || bool.op()=="!=") ) return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true ); // Vs immediate @@ -415,18 +438,23 @@ public class x86_64_v2 extends Machine { private Node con( ConstantNode con ) { if( !con._con.isConstant() ) - return new ConstantNode(con); // Default unknown caller inputs + return ConstantNode.raw(con); // Default unknown caller inputs + String ext = con instanceof ExternNode ext0 ? ext0._extern : null; return switch (con._con) { - case TypeInteger ti -> new IntX86(con); - case TypeFloat tf -> new FltX86(con); - case TypeFunPtr tfp -> new TFPX86(con); - case TypeMemPtr tmp -> new TMPX86(con); + case TypeInteger ti -> new IntX86(con,ext); + case TypeFloat tf -> new FltX86(con,ext); + case TypeMemPtr tmp -> new TMPX86(con,ext); + case TypeFunPtr tfp -> new TFPX86(tfp,ext); case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con); + case Type t -> t == Type.NIL ? new IntX86(con,null) : ConstantNode.raw(con); }; } + private Node fptr( FunPtrNode con ) { + return new TFPX86(con); + } + private Node i2f8(ToFloatNode tfn) { assert tfn.in(1)._type instanceof TypeInteger ti; return new I2f8X86(tfn); @@ -439,7 +467,9 @@ public class x86_64_v2 extends Machine { String op = "!="; if( iff.in(1) instanceof BoolNode bool ) op = swap ? IfNode.swap(bool.op()) : bool.op(); else if( iff.in(1)==null ) op = "=="; // Never-node cutout - else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); + else iff.setDef(1, new BoolNode.NE(iff.in(1), + ConstantNode.raw(TypeInteger.ZERO), + (byte)(iff.in(1)._type instanceof TypeFloat ? 2 : 1))); return new JmpX86(iff, op); } @@ -462,7 +492,7 @@ public class x86_64_v2 extends Machine { private Node prj( ProjNode prj ) { TypeInteger ret = cReturn(prj); if( ret!=null ) return new ExtendX86(prj,ret); - return new ProjX86(prj); + return prj.in(0) instanceof StartNode ? new ProjNode(prj) : new ProjX86(prj); } private Node sar(SarNode sar) { @@ -549,7 +579,7 @@ public class x86_64_v2 extends Machine { private int imm( Node xval ) { assert val == null && imm == 0; - if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti) { + if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti && ti.isConstant() && imm32(ti.value()) ) { val = null; imm = (int) ti.value(); assert imm == ti.value(); // In 32-bit range |
