summaryrefslogtreecommitdiff
path: root/chapter21
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-03-19 09:54:45 -0700
committerCliff Click <cliffc@acm.org>2025-03-19 09:54:45 -0700
commit442b5060a7f5857cfdedcc69384d90fd5fed9036 (patch)
tree516ea2c6249f11268497ef1f60aa9fe6779f0c12 /chapter21
parent352c6927252137a252ab942c83695890fb332004 (diff)
downloadSimple-442b5060a7f5857cfdedcc69384d90fd5fed9036.tar.gz
Simple-442b5060a7f5857cfdedcc69384d90fd5fed9036.zip
constant pool
Diffstat (limited to 'chapter21')
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/SB.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java91
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java32
7 files changed, 161 insertions, 50 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/SB.java b/chapter21/src/main/java/com/seaofnodes/simple/SB.java
index af49e52b..978fbed9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/SB.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/SB.java
@@ -41,13 +41,9 @@ public final class SB {
public SB hex2(int s) { return hex1(s>> 8).hex1(s); }
// 4 bytes, 8 hex digits, 32 bits, Big Endian
public SB hex4(int s) { return hex2(s>>16).hex2(s); }
- //public SB hex4(int s) {
- //for( int i=0; i<8; i++ ) {
- // int digit = (s>>((7-i)*4)) & 0xf;
- // _sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
- //}
- //return this;
- //
+ // 8 bytes, 16 hex digits, 64 bits, Big Endian
+ public SB hex8(long s) { return hex4((int)(s>>32)).hex4((int)s); }
+
// Fixed width field
public SB fix( int sz, String s ) {
for( int i=0; i<sz; i++ )
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
index 56e5960a..e227eaff 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -4,12 +4,9 @@ import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.HashMap;
+import java.util.*;
/**
@@ -67,6 +64,13 @@ public class Encoding {
add4((int) i64 );
add4((int)(i64>>32));
}
+ public int read4(int idx) {
+ byte[] buf = _bits.buf();
+ return buf[idx] | (buf[idx+1]&0xFF) <<8 | (buf[idx+2]&0xFF)<<16 | (buf[idx+3]&0xFF)<<24;
+ }
+ public long read8(int idx) {
+ return (read4(idx) & 0xFFFFFFFFL) | read4(idx+4);
+ }
// This buffer is invalid/moving until after all encodings are written
public byte[] bits() { return _bits.buf(); }
@@ -80,6 +84,11 @@ public class Encoding {
buf[idx+3] = (byte)(val>>24);
}
+ void pad8() {
+ while( (_bits.size()+7 & -8) > _bits.size() )
+ _bits.write(0);
+ }
+
// Nodes need "relocation" patching; things done after code is placed.
// Record src and dst Nodes.
@@ -111,10 +120,10 @@ public class Encoding {
// addressing to load it
public final HashMap<Node,Type> _bigCons = new HashMap<>();
+ public final HashMap<Node,Integer> _cpool = new HashMap<>();
public void largeConstant( Node relo, Type t ) {
assert t.isConstant();
_bigCons.put(relo,t);
- // TODO:
}
void encode() {
@@ -128,6 +137,10 @@ public class Encoding {
// Record opcode start and length.
writeEncodings();
+ // Write any large constants into a constant pool; they
+ // are accessed by RIP-relative addressing.
+ writeConstantPool();
+
// Short-form RIP-relative support: replace long encodings with short
// encodings and compact the code, changing all the offsets.
compactShortForm();
@@ -180,9 +193,6 @@ public class Encoding {
// Pick out the T/F projections
CProjNode t = iff.cproj(0);
CProjNode f = iff.cproj(1);
- //CProjNode t = (CProjNode)bb.out(bb.nOuts()-1);
- //CProjNode f = (CProjNode)bb.out(bb.nOuts()-2);
- //if( t._idx==1 ) { CProjNode tmp=f; f=t; t=tmp; }
int tld = t.loopDepth(), fld = f.loopDepth(), bld = bb.loopDepth();
// Decide entering or exiting a loop
if( tld==bld ) {
@@ -235,11 +245,48 @@ public class Encoding {
}
}
}
+ pad8();
}
+ // Write the constant pool
+ private void writeConstantPool() {
+ // TODO: Check for cpool dups
+ HashSet<Type> ts = new HashSet<>();
+ for( Type t : _bigCons.values() ) {
+ if( ts.contains(t) )
+ throw Utils.TODO(); // Dup! Compress!
+ ts.add(t);
+ }
+
+ // Write the 8-byte constants
+ for( Node relo : _bigCons.keySet() ) {
+ Type t = _bigCons.get(relo);
+ if( t.log_size()==3 ) {
+ // Map from relo to constant start
+ _cpool.put(relo,_bits.size());
+ long x = t instanceof TypeInteger ti
+ ? ti.value()
+ : Double.doubleToRawLongBits(((TypeFloat)t).value());
+ add8(x);
+ }
+ }
+
+ // Write the 4-byte constants
+ for( Node relo : _bigCons.keySet() ) {
+ Type t = _bigCons.get(relo);
+ if( t.log_size()==2 ) {
+ // Map from relo to constant start
+ _cpool.put(relo,_bits.size());
+ int x = t instanceof TypeInteger ti
+ ? (int)ti.value()
+ : Float.floatToRawIntBits((float)((TypeFloat)t).value());
+ add4(x);
+ }
+ }
+ }
- // Short-form RIP-relative support: replace long encodings with short
- // encodings and compact the code, changing all the offsets.
+ // Short-form RIP-relative support: replace short encodings with long
+ // encodings and expand the code, changing all the offsets.
private void compactShortForm() {
int len = _code._cfg._len;
int[] oldStarts = new int[len];
@@ -253,8 +300,8 @@ public class Encoding {
// Check the size of short jumps, adjust the block starts for a whole
// pass over all blocks. If some jumps go long, they might stretch the
- // distance for other jumps, so another pass is needed;
- int slide= -1;
+ // distance for other jumps, so another pass is needed.
+ int slide = -1;
while( slide != 0) { // While no fails
slide = 0;
for( int i=0; i<len; i++ ) {
@@ -268,12 +315,20 @@ public class Encoding {
assert _opStart[target._nid] > 0;
int delta = _opStart[target._nid] - _opStart[bb._nid];
byte opLen = riprel.encSize(delta);
+ // Recorded size is smaller than the current size?
if( _opLen[bb._nid] < opLen ) {
+ // Start sliding the code down; record slide amount and new size
slide += opLen - _opLen[bb._nid];
_opLen[bb._nid] = opLen;
}
}
}
+
+ // CPool padding is non-linear; in rare cases padding can force a
+ // larger size... which will shrink the padding and allow the
+ // short form to work. Too bad.
+ if( !_cpool.isEmpty() )
+ pad8();
}
@@ -299,9 +354,15 @@ public class Encoding {
// Walk the local code-address relocations
for( Node src : _internals.keySet() ) {
Node dst = _internals.get(src);
+ int target = _opStart[dst._nid];
+ int start = _opStart[src._nid];
+ ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start);
+ }
+
+ for( Node src : _cpool.keySet() ) {
+ int target = _cpool.get(src);
int start = _opStart[src._nid];
- ((RIPRelSize)src).patch(this, start, _opLen[src._nid], _opStart[dst._nid] - start);
+ ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start);
}
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
index 2b089331..b2673396 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
@@ -9,14 +9,11 @@ import com.seaofnodes.simple.type.TypeFloat;
//FMOV (scalar, immediate)
//Floating-point move immediate.
-public class FloatARM extends ConstantNode implements MachNode {
+public class FloatARM extends ConstantNode implements MachNode, RIPRelSize {
FloatARM(ConstantNode con) { super(con); }
- // Register mask allowed on input i. 0 for no register.
+ @Override public String op() { return "ld8"; }
@Override public RegMask regmap(int i) { return null; }
-
- // General int registers
@Override public RegMask outregmap() { return arm.DMASK; }
-
@Override public boolean isClone() { return true; }
@Override public FloatARM copy() { return new FloatARM(this); }
@@ -25,9 +22,16 @@ public class FloatARM extends ConstantNode implements MachNode {
short dst = (short)(enc.reg(this) - arm.D_OFFSET);
double d = ((TypeFloat)_con).value();
long x = Double.doubleToRawLongBits(d);
- // Any number that can be expressed as +/-n * 2-r,where n and r are integers, 16 <= n <= 31, 0 <= r <= 7.
- int body = arm.load_pc(0b01011100, 0, dst);
- enc.add4(body);
+ enc.add4(arm.load_pc(0b01011100, 0, dst));
+ }
+
+ // Delta is from opcode start.
+ @Override public byte encSize(int delta) { return 4; }
+
+ // Delta is from opcode start
+ @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) {
+ short dst = (short)(enc.reg(this) - arm.D_OFFSET);
+ enc.add4(arm.load_pc(0b01011100, delta, dst));
}
// Human-readable form appended to the SB. Things like the encoding,
@@ -35,10 +39,7 @@ public class FloatARM extends ConstantNode implements MachNode {
// Just something like "ld4\tR17=[R18+12] // Load array base".
// General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
- _con.print(sb.p(code.reg(this)).p(" #"));
+ _con.print(sb.p(code.reg(this)).p(" = #"));
}
- @Override public String op() {
- return "fld"; // Some fancier encoding
- }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
index 2d253ff3..d5d56068 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
@@ -7,9 +7,9 @@ import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.TypeFloat;
-public class FltRISC extends ConstantNode implements MachNode{
+public class FltRISC extends ConstantNode implements MachNode, RIPRelSize {
FltRISC(ConstantNode con) { super(con); }
- @Override public String op() { return "flw"; }
+ @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; }
@@ -24,8 +24,21 @@ public class FltRISC extends ConstantNode implements MachNode{
enc.add4(riscv.i_type(0x07, dst, 0x03, dst, 0));
}
+ // Delta is from opcode start.
+ // TODO: always size 8?
+ @Override public byte encSize(int delta) { return 8; }
+
+ // Delta is from opcode start
+ @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) {
+ short dst = (short)(enc.reg(this) - riscv.F_OFFSET);
+ // AUIPC dst,#hi20_constant_pool
+ enc.patch4(opStart , riscv.u_type(0b0010111, dst, delta));
+ // Load dst,[dst+#low12_constant_pool]
+ enc.patch4(opStart+4, riscv.i_type(0x07, dst, 0x03, dst, delta));
+ }
+
@Override public void asm(CodeGen code, SB sb) {
- _con.print(sb.p(code.reg(this)).p(" #"));
+ _con.print(sb.p(code.reg(this)).p(" = #"));
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
index 9055d67f..307d745f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
@@ -4,9 +4,10 @@ import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-public class FltX86 extends ConstantNode implements MachNode {
+public class FltX86 extends ConstantNode implements MachNode, RIPRelSize {
+ private byte _encSize;
FltX86(ConstantNode con ) { super(con); }
- @Override public String op() { return "fld"; }
+ @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; }
@@ -14,24 +15,33 @@ public class FltX86 extends ConstantNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public void encoding( Encoding enc ) {
- enc.largeConstant(this,_con);
// Load the constant into a FPR
// movsd xmm, [rip + 0]
// F2 0F 10 /r MOVSD xmm1, m64
+ _encSize = 1/*Fop*/+0/*REX*/+2/*op*/+1/*MODRM*/+4/*offset*/;
short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
-
+ enc.largeConstant(this,_con);
// Fopcode
enc.add1(0xF2);
// rex prefix must come next (REX.W is not set)
- x86_64_v2.rexF(dst, 0, 0, false, enc);
-
+ _encSize += x86_64_v2.rexF(dst, 0, 0, false, enc);
enc.add1(0x0F).add1(0x10);
-
// hard-code rip here
enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x05));
enc.add4(0);
}
+ // Delta is from opcode start
+ @Override public byte encSize(int delta) {
+ // TODO: 1-byte RIP offset?
+ return (byte)_encSize;
+ }
+
+ // Delta is from opcode start
+ @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) {
+ enc.patch4(opStart+opLen-4,delta-opLen);
+ }
+
@Override public void asm(CodeGen code, SB sb) {
_con.print(sb.p(code.reg(this)).p(" = #"));
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index ff045ef8..dc3b86a8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -114,11 +114,13 @@ public class x86_64_v2 extends Machine {
return rex(reg, ptr, idx, true);
}
- // rex for floats
- // don't need to use REX if 0x40
- public static void rexF(int reg, int ptr, int idx, boolean wide, Encoding enc) {
+ // rex for floats. Return size (0 or 1)
+ // don't need to use REX if 0x40.
+ public static byte rexF(int reg, int ptr, int idx, boolean wide, Encoding enc) {
int rex = rex(reg, ptr, idx, wide);
- if (rex != 0x40) enc.add1(rex);
+ if (rex == 0x40) return 0;
+ enc.add1(rex);
+ return 1;
}
// Function used for encoding indirect memory addresses
// Does not always generate SIB byte e.g index == -1.
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 2ac94b46..ab997ab9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -3,9 +3,9 @@ package com.seaofnodes.simple.print;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeMem;
-import com.seaofnodes.simple.type.TypeRPC;
+import com.seaofnodes.simple.type.*;
public abstract class ASMPrinter {
@@ -18,6 +18,34 @@ public abstract class ASMPrinter {
for( int i=0; i<code._cfg._len; i++ )
if( code._cfg.at(i) instanceof FunNode fun )
iadr = print(iadr,sb,code,fun,i);
+
+ // Skip padding
+ while( ((iadr+7) & -8) > iadr )
+ iadr++;
+
+ // constant pool
+ Encoding enc = code._encoding;
+ if( !enc._bigCons.isEmpty() ) {
+ sb.p("--- Constant Pool ------").nl();
+ for( Node relo : enc._bigCons.keySet() ) {
+ Type t = enc._bigCons.get(relo);
+ if( t.log_size()==3 ) {
+ sb.hex2(iadr).p(" ").hex8(enc.read8(iadr)).p(" ");
+ t.print(sb).nl();
+ iadr += 8;
+ }
+ }
+ for( Node relo : enc._bigCons.keySet() ) {
+ Type t = enc._bigCons.get(relo);
+ if( t.log_size()==2 ) {
+ sb.hex2(iadr).p(" ").hex4(enc.read4(iadr)).fix(9,"");
+ t.print(sb).nl();
+ iadr += 4;
+ }
+ }
+ }
+
+
return sb;
}