diff options
| author | Cliff Click <cliffc@acm.org> | 2025-03-19 09:54:45 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-03-19 09:54:45 -0700 |
| commit | 442b5060a7f5857cfdedcc69384d90fd5fed9036 (patch) | |
| tree | 516ea2c6249f11268497ef1f60aa9fe6779f0c12 /chapter21/src/main/java/com | |
| parent | 352c6927252137a252ab942c83695890fb332004 (diff) | |
| download | Simple-442b5060a7f5857cfdedcc69384d90fd5fed9036.tar.gz Simple-442b5060a7f5857cfdedcc69384d90fd5fed9036.zip | |
constant pool
Diffstat (limited to 'chapter21/src/main/java/com')
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; } |
