diff options
| author | Cliff Click <cliffc@acm.org> | 2026-09-20 22:38:58 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-09-20 22:38:58 -0700 |
| commit | 40b33cb6f8b8dc4d8551c3b522e7c5682a44540a (patch) | |
| tree | e44d0380390109e3597bc5a1b1744e715cc30b62 /chapter23/src | |
| parent | 1e527b16b28f31b08cbb36b7b1bf2d689487a989 (diff) | |
| download | Simple-40b33cb6f8b8dc4d8551c3b522e7c5682a44540a.tar.gz Simple-40b33cb6f8b8dc4d8551c3b522e7c5682a44540a.zip | |
Final reg-alloc across chapters cleanup
Diffstat (limited to 'chapter23/src')
9 files changed, 84 insertions, 25 deletions
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/IFG.java index bc14aadd..ecff9aac 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/IFG.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/IFG.java @@ -522,7 +522,7 @@ abstract public class IFG { if( reg == -1 && alrg._mask.size1() ) reg = alrg._mask.firstReg(); if( reg != -1 ) { - mask.clr(alrg._reg); + mask.clr(reg); if( mask.size1() ) return mask.firstReg(); } diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java index 1e5d2094..8967d654 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java @@ -3,7 +3,6 @@ package com.seaofnodes.simple.node.cpus.arm; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.LoadNode; import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.type.TypeFloat; import com.seaofnodes.simple.util.SB; // Load memory addressing on ARM @@ -17,20 +16,15 @@ public class LoadARM extends MemOpARM { super(ld, base, idx, off, 0); } @Override public String op() { return "ld"+_sz; } - @Override public RegMask outregmap() { return arm.MEM_MASK; } + @Override public RegMask outregmap() { return size() >= 4 ? arm.MEM_MASK : arm.RMASK; } private static final int[] OP_LOADS = new int[]{ arm.OP_LOAD_IMM_8, arm.OP_LOAD_IMM_16, arm.OP_LOAD_IMM_32, arm.OP_LOAD_IMM_64, }; - private int imm_op() { - return _declaredType == TypeFloat.F32 ? arm.OPF_LOAD_IMM_32 - : _declaredType == TypeFloat.F64 ? arm.OPF_LOAD_IMM_64 - : OP_LOADS[_declaredType.log_size()]; - } private static final int[] OP_LOAD_RS = new int[]{ arm.OP_LOAD_R_8 , arm.OP_LOAD_R_16 , arm.OP_LOAD_R_32 , arm.OP_LOAD_R_64, }; // ldr(immediate - unsigned offset) | ldr(register) @Override public void encoding( Encoding enc ) { - ldst_encode(enc, imm_op(), OP_LOAD_RS[_declaredType.log_size()], this, size()); + ldst_encode(enc, OP_LOADS[Integer.numberOfTrailingZeros(size())], OP_LOAD_RS[_declaredType.log_size()], this, size()); } @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)).p(","); diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java index e877931d..01066f47 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java @@ -44,7 +44,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode { if( i==1 ) return null; // memory if( i==2 ) return arm.RMASK; // ptr/base if( i==3 ) return arm.RMASK; // off/index - if( i==4 ) return arm.RMASK; // value + if( i==4 ) return size() >= 4 ? arm.MEM_MASK : arm.RMASK; // value return null; // Anti-dependence } @@ -53,6 +53,15 @@ public abstract class MemOpARM extends MemOpNode implements MachNode { short ptr = enc.reg(ptr()); short off = enc.reg(off()); short val = enc.reg(xval); + // The allocated register selects integer vs SIMD/FP encoding, even for + // bitwise copies. ARM numbers each register bank from zero in the opcode. + boolean fp = val >= arm.D0; + assert !fp || size >= 4; + if( fp ) { + opcode_imm |= 1<<4; + opcode_reg |= 1<<5; + val -= arm.D0; + } int body = off() == null ? arm.load_str_imm(opcode_imm, _off, ptr, val, size) : arm.indr_adr(opcode_reg, off, arm.STORE_LOAD_OPTION.SXTX, 0, ptr, val); diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java index 91385ac9..4fd8ac79 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java @@ -3,7 +3,6 @@ package com.seaofnodes.simple.node.cpus.arm; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.StoreNode; -import com.seaofnodes.simple.type.TypeFloat; import com.seaofnodes.simple.util.SB; // Store memory addressing on ARM @@ -24,16 +23,11 @@ public class StoreARM extends MemOpARM { @Override public RegMask outregmap() { return null; } private static final int[] OP_STORES = new int[]{ arm.OP_STORE_IMM_8, arm.OP_STORE_IMM_16, arm.OP_STORE_IMM_32, arm.OP_STORE_IMM_64, }; - private int imm_op() { - return _declaredType == TypeFloat.F32 ? arm.OPF_STORE_IMM_32 - : _declaredType == TypeFloat.F64 ? arm.OPF_STORE_IMM_64 - : OP_STORES[_declaredType.log_size()]; - } private static final int[] OP_STORE_RS = new int[]{ arm.OP_STORE_R_8, arm.OP_STORE_R_16, arm.OP_STORE_R_32, arm.OP_STORE_R_64, }; @Override public void encoding( Encoding enc ) { - ldst_encode(enc, imm_op(), OP_STORE_RS[_declaredType.log_size()], val(), size()); + ldst_encode(enc, OP_STORES[Integer.numberOfTrailingZeros(size())], OP_STORE_RS[_declaredType.log_size()], val(), size()); } @Override public void asm(CodeGen code, SB sb) { asm_address(code,sb).p(","); diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 716f7cb7..db179754 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -169,7 +169,7 @@ public class arm extends Machine { public static int OPF_STORE_R_64 = 0b11111100001; public static int OPF_STORE_R_32 = 0b10111100001; - public static int OPF_STORE_IMM_32 = 0b1111110100; + public static int OPF_STORE_IMM_32 = 0b1011110100; public static int OPF_STORE_IMM_64 = 0b1111110100; diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java index 70ddd435..044ad4ed 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -11,6 +11,23 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter20Test { + @Test public void testAllocatorFixedNeighbor() throws Exception { com.seaofnodes.simple.codegen.RegAllocTestSupport.uncoloredFixedNeighbor(); } + + @Test public void testNarrowStoreMasks() { + for( String type : new String[]{"i8","u8","i16","u16"} ) { + CodeGen code = new CodeGen("struct S { "+type+" x; }; S !s=new S; s.x=arg; return 0;") + .driver(CodeGen.Phase.RegAlloc,"x86_64_v2","SystemV"); + int stores=0; + for( var bb : code._cfg ) + for( var node : bb.outs() ) + if( node instanceof com.seaofnodes.simple.node.cpus.x86_64_v2.StoreX86 st ) { + stores++; + assertEquals(-1,st.regmap(4).nextReg((short)15)); + } + assertEquals(1,stores); + } + } + @Test public void testInlinedReturnValue() { String src = """ struct S { int x; }; diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java index f84a7237..3be634d1 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -13,6 +13,38 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter21Test { + @Test public void testArmFloatMemory() throws IOException { + for( String type : new String[]{"f32","f64"} ) { + String src = type+"[] !a=new "+type+"[3]; a[arg]=1.25; return a[1];"; + CodeGen code = new CodeGen(src).driver("arm","SystemV",null); + byte[] image = new byte[1<<20]; + byte[] bits = code._encoding.bits(); + System.arraycopy(bits,0,image,0,bits.length); + EvalArm64 cpu = new EvalArm64(image,1<<16); + cpu.regs[arm.X0]=1; + assertEquals(0,cpu.step(1000)); + assertEquals(1.25,cpu.fregs[0],0); + } + // Independently exercise both SIMD widths and addressing modes. Keep + // the GPR value different so accidentally reading that bank is visible. + for( boolean wide : new boolean[]{false,true} ) + for( boolean indexed : new boolean[]{false,true} ) { + EvalArm64 cpu = new EvalArm64(new byte[512],256); + cpu.regs[1]=128; cpu.regs[2]=16; cpu.regs[3]=99; + cpu.fregs[3]=-13.25; + int store = (wide ? 0xFD000000 : 0xBD000000) | ((16/(wide?8:4))<<10) | (1<<5) | 3; + if( indexed ) store=(wide ? 0xFC226823 : 0xBC226823); // STR D3/S3,[X1,X2] + cpu.st4(0,store); + cpu.st4(4,store | (1<<22)); // LDR to the same SIMD register. + assertEquals(0,cpu.step(1)); + assertEquals(-13.25,wide ? cpu.ld8f(144) : cpu.ld4f(144),0); + cpu.fregs[3]=0; + assertEquals(0,cpu.step(1)); + assertEquals(-13.25,cpu.fregs[3],0); + } + } + + @Test public void testArmCallInstructions() { EvalArm64 cpu = new EvalArm64(new byte[512],256); for( int delta : new int[]{4,32,-4} ) { diff --git a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java index 54d08e19..46827235 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java @@ -481,7 +481,7 @@ public class EvalArm64 { switch(opc) { case 0x1: { if(opcode1 == arm.OPF_STORE_R_32) { - st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + st4((int)regs[rn] + (int)regs[rm], Float.floatToRawIntBits((float)fregs[rdid])); }else { trap = (2+1); } @@ -520,7 +520,7 @@ public class EvalArm64 { case 0x0: { // store if(opcode1 == arm.OPF_STORE_IMM_32) { - st4((int)rval, (int)regs[rdid]); + st4((int)rval, Float.floatToRawIntBits((float)fregs[rdid])); } else trap = (2+1); rdid = -1; @@ -529,7 +529,7 @@ public class EvalArm64 { case 0x1: { // LDR (immediate) if(opcode1 == arm.OPF_LOAD_IMM_32) { - frval = ld4s((int)rval); + frval = ld4f((int)rval); } else trap = (2+1); break; } @@ -683,7 +683,7 @@ public class EvalArm64 { switch(opc) { case 0x1: { if(opcode1 == arm.OPF_STORE_R_64) { - st8((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + st8((int)regs[rn] + (int)regs[rm], Double.doubleToRawLongBits(fregs[rdid])); }else { trap = (2+1); } @@ -711,7 +711,7 @@ public class EvalArm64 { int base = ir >> 5 & 0x1F; int imm = (ir >> 10) & 0xFFF; - imm *= 4; + imm *= 8; is_f = true; rval = regs[base] + imm; int opc = (ir >> 22) & 0x3; @@ -721,7 +721,7 @@ public class EvalArm64 { case 0x0: { // store if(opcode1 == arm.OPF_STORE_IMM_64) { - st8((int)rval, regs[rdid]); + st8((int)rval, Double.doubleToRawLongBits(fregs[rdid])); } else trap = (2+1); rdid = -1; @@ -730,7 +730,7 @@ public class EvalArm64 { case 0x1: { // LDR (immediate) if(opcode1 == arm.OPF_LOAD_IMM_64) { - frval = ld8((int)rval); + frval = ld8f((int)rval); } else trap = (2+1); break; } diff --git a/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java b/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java index ec666653..f0830f1b 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java @@ -29,6 +29,19 @@ public class RegAllocTestSupport { return code; } + public static void uncoloredFixedNeighbor() throws Exception { + CodeGen code = graph(); + RegAlloc alloc = new RegAlloc(code); + Op def = new Op(new RegMask(3L),null,null,false,code._start); + LRG lrg = alloc.newLRG(def); + LRG neighbor = new LRG((short)99); + neighbor._mask = A; + lrg.addNeighbor(neighbor); // Uncolored, but its only possible color is A. + var bias = IFG.class.getDeclaredMethod("biasColorNeighbors",RegAlloc.class,Node.class,RegMask.class); + bias.setAccessible(true); + assertEquals((short)1,bias.invoke(null,alloc,def,new RegMaskRW(3L,0L))); + } + public static void masks() { for( int reg : new int[]{0,63,64,65,127} ) { RegMask mask = new RegMask(reg); |
