summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/cpus
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-08-10 11:11:18 -0700
committerCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
commitd32f97238c903765dec4e9a9f3cbfa5fd12cded6 (patch)
treea5ac731801ef7066bab6359c4e85c2bdd20082a6 /src/main/java/com/seaofnodes/simple/node/cpus
parentb5ebb2032aa04cf4506d533127d373d4cf5a25c6 (diff)
downloadSimple-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')
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/FltARM.java (renamed from src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java)9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java12
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java12
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java36
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java18
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java105
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java11
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java35
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java41
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java12
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java31
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java12
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java114
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java12
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java1
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java15
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java48
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java21
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java148
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