diff options
Diffstat (limited to 'chapter21/src/main')
8 files changed, 139 insertions, 11 deletions
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 67eeb3c2..0162bc84 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -53,6 +53,10 @@ public class Encoding { public Encoding add1( int op ) { _bits.write(op); return this; } + public void add2( int op ) { + _bits.write(op ); + _bits.write(op>> 8); + } // Little endian write of a 32b opcode public void add4( int op ) { _bits.write(op ); diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 0ba47317..f42dae75 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -4,9 +4,10 @@ import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.cpus.riscv.riscv; import com.seaofnodes.simple.type.TypeFunPtr; -public class TFPARM extends ConstantNode implements MachNode { +public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { TFPARM( ConstantNode con ) { super(con); } @Override public String op() { return "ldx"; } @Override public RegMask regmap(int i) { return null; } @@ -22,6 +23,28 @@ public class TFPARM extends ConstantNode implements MachNode { arm.imm_inst(enc,this,0b1001000100,0); enc.add4(adrp); } + + @Override public byte encSize(int delta) { + if( -(1L<<12) <= delta && delta < (1L<<12) ) return 4; + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); + if(opLen ==4 ) { + // opstart of add + int next = opStart + opLen; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); + // low 12 bits via add + enc.patch4(next, arm.imm_inst_l(enc, this, 0b1001000100, delta & 0xfff)); + } else { + throw Utils.TODO(); + } + } + @Override public void asm(CodeGen code, SB sb) { String reg = code.reg(this); _con.print(sb.p(reg).p(" #")); diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index b35f600a..4b0781f2 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -224,6 +224,13 @@ public class arm extends Machine { enc.add4(body); } + public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + int body = imm_inst(opcode, imm12&0xFFF, reg1, self); + return body; + } + // for normal add, reg1, reg2 cases (reg-to-reg) // using shifted-reg form public static int r_reg(int opcode, int shift, int rm, int imm6, int rn, int rd) { diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index 873a07ce..6cb219df 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -6,7 +6,7 @@ import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.TypeFunPtr; -public class TFPRISC extends ConstantNode implements MachNode { +public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { TFPRISC(ConstantNode con) { super(con); } @Override public String op() { return "ldx"; } @Override public RegMask regmap(int i) { return null; } @@ -26,6 +26,27 @@ public class TFPRISC extends ConstantNode implements MachNode { enc.add4(addi); } + @Override public byte encSize(int delta) { + if( -(1L<<11) <= delta && delta < (1L<<11) ) return 4; + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); + if( opLen==4 ) { + // AUIPC (upper 20 bits) + // opstart of add + int next = opStart + opLen; + enc.patch4(opStart,riscv.u_type(0b0010111, rpc, delta)); + // addi(low 12 bits) + enc.patch4(next,riscv.i_type(0b0010011, rpc, 0, rpc, delta & 0xFFF)); + // addi + } else { + throw Utils.TODO(); + } + } + @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/LoadX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java index 39525ed1..6dd3e3dc 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java @@ -4,6 +4,8 @@ import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.LoadNode; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; public class LoadX86 extends MemOpX86 { LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) { @@ -13,11 +15,42 @@ public class LoadX86 extends MemOpX86 { @Override public RegMask outregmap() { return x86_64_v2.MEM_MASK; } @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 + // Use movsx and movzx + short dst = enc.reg(this ); short ptr = enc.reg(ptr()); short idx = enc.reg(idx()); - enc.add1(x86_64_v2.rex(dst, ptr, idx)); - enc.add1(0x8B); // opcode + if (_declaredType != TypeInteger.U32) { + enc.add1(x86_64_v2.rex(dst, ptr, idx)); + } + + if(_declaredType == TypeInteger.I8) { + // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8 + enc.add1(0x0F); + enc.add1(0xBE); + } else if(_declaredType == TypeInteger.I16) { + // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16 + enc.add1(0x0F); + enc.add1(0xBF); + } else if(_declaredType == TypeInteger.I32) { + // sign extend: REX.W + 63 /r MOVSXD r64, r/m32 + enc.add1(0x63); + } else if(_declaredType == TypeInteger.U8) { + // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8 + enc.add1(0x0F); + enc.add1(0xB6); + } else if(_declaredType == TypeInteger.U16) { + // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16 + enc.add1(0x0F); + enc.add1(0xB7); + } else if(_declaredType == TypeInteger.U32) { + // zero extend: 8B /r MOV r32, r/m32 + enc.add1(0x8B); + } else if(_declaredType == TypeInteger.BOT) { + // REX.W + 8B /r MOV r64, r/m64 + enc.add1(0x8B); + } // includes modrm internally x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc); diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java index 4a54663d..8c2e0612 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -2,6 +2,7 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.StoreNode; import java.util.BitSet; @@ -27,13 +28,27 @@ public class StoreX86 extends MemOpX86 { short idx = enc.reg(idx()); short src = enc.reg(val()); - enc.add1(x86_64_v2.rex(src, ptr, idx)); + int imm_op = x86_64_v2.selectOpcodeForImmStore(_imm); + if(src == -1 && _imm != 0) { + if(imm_op == -1) {enc.add1(x86_64_v2.rex(src, ptr, idx));enc.add1(0xC7); } + else enc.add1(imm_op); + } else { - // switch on opcode depending on instruction - enc.add1( src == -1 ? 0xC7 : 0x89 ); + if(_declaredType.log_size() == 0) enc.add1(0x88); + if(_declaredType.log_size() == 1) enc.add1(0x89); + if(_declaredType.log_size() == 2) enc.add1(0x89); + if(_declaredType.log_size() == 3) {enc.add1(x86_64_v2.rex(src, ptr, idx)); enc.add1(0x89);} + } x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src, enc); - if( src == -1 ) enc.add4(_imm); + if( src == -1 ) { + switch (x86_64_v2.imm_size(_imm)) { + case 8: enc.add1(_imm); break; + case 16: enc.add2(_imm); break; + case 32: enc.add4(_imm); break; + case 64: enc.add8(_imm); break; + } + } } // General form: "stN [base + idx<<2 + 12],val" diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java index 13b9f8a3..be4d1a83 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java @@ -3,11 +3,12 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; import com.seaofnodes.simple.*; 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; // Function constants -public class TFPX86 extends ConstantNode implements MachNode { +public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { TFPX86( ConstantNode con ) { super(con); } @Override public String op() { return _con == Type.NIL ? "xor" : "ldx"; @@ -42,6 +43,15 @@ public class TFPX86 extends ConstantNode implements MachNode { enc.add4(0); } + @Override public byte encSize(int delta) { + return 7; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart + 3, delta - 7); + } + // Human-readable form appended to the SB. Things like the encoding, // indentation, leading address or block labels not printed here. // Just something like "ld4\tR17=[R18+12] // Load array base". 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 9d7b1a26..1d30bc4b 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 @@ -109,6 +109,20 @@ public class x86_64_v2 extends Machine { if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X return rex; } + // return opcode for optimised immediate store + public static int selectOpcodeForImmStore(long imm) { + if(imm8(imm)) return 0xC6; + if(imm16(imm)) return 0xC7; + if(imm32(imm)) return 0xC7; + return -1; + } + // return the size of the immediate + public static int imm_size(long imm) { + if(imm8(imm)) return 8; + if(imm16(imm)) return 16; + if(imm32(imm)) return 32; + return 64; + } public static int rex(int reg, int ptr, int idx) { return rex(reg, ptr, idx, true); @@ -410,16 +424,17 @@ public class x86_64_v2 extends Machine { } public static boolean imm8( long imm ) { return -128 <= imm && imm <= 127; } + public static boolean imm16(long imm) {return -32768 <= imm && imm <= 32767; } public static boolean imm32( long imm ) { return (int)imm==imm; } // Attempt a full LEA-style break down. private Node add(AddNode add) { Node lhs = add.in(1); Node rhs = add.in(2); - if( lhs instanceof LoadNode ld && ld.nOuts() == 1 ) + if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && ld._declaredType.log_size() >= 3) return new AddMemX86(add, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val); - if(rhs instanceof LoadNode ld && ld.nOuts() == 1) + if(rhs instanceof LoadNode ld && ld.nOuts() == 1 && ld._declaredType.log_size() >= 3) throw Utils.TODO(); // Swap load sides // Attempt a full LEA-style break down. |
