summaryrefslogtreecommitdiff
path: root/chapter21/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-03-15 12:06:11 -0700
committerCliff Click <cliffc@acm.org>2025-03-15 12:06:11 -0700
commitb6cbd3d7b7698922e60e2c3eadadab51a430efe1 (patch)
tree047eadd501d6c01363d8b3b10d3f09fd1df0676d /chapter21/src
parenta36369843133a170718006600890d12ceb66a553 (diff)
downloadSimple-b6cbd3d7b7698922e60e2c3eadadab51a430efe1.tar.gz
Simple-b6cbd3d7b7698922e60e2c3eadadab51a430efe1.zip
Progress towards no crashes
Multi-part constant expansion was buggy when splitting down into functions. Improved printing for RISC multi-part constants.
Diffstat (limited to 'chapter21/src')
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/SB.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java11
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java30
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java56
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java2
11 files changed, 79 insertions, 85 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/SB.java b/chapter21/src/main/java/com/seaofnodes/simple/SB.java
index 72649a39..31fbb7d4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/SB.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/SB.java
@@ -29,23 +29,25 @@ public final class SB {
public SB p( int s ) { _sb.append(s); return this; }
public SB p( long s ) { _sb.append(s); return this; }
public SB p( boolean s) { _sb.append(s); return this; }
- // 2 hex digits
- public SB hex2(int s) {
+ // 1 byte, 2 hex digits, 8 bits
+ public SB hex1(int s) {
int digit = (s>>4) & 0xf;
_sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
digit = s & 0xf;
_sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
return this;
}
- // 4 hex digits
- public SB hex4(int s) {
- assert (s>>4*4)==0; // Fits in 16 bits
- for( int i=0; i<4; i++ ) {
- int digit = (s>>((3-i)*4)) & 0xf;
- _sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit));
- }
- return this;
- }
+ // 2 bytes, 4 hex digits, 16 bits, Big Endian
+ 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;
+ //
// 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/node/ConstantNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index f7ebc006..699ee76f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -48,7 +48,7 @@ public class ConstantNode extends Node {
if( fun._name != null )
return sb.append("{ ").append(fun._name).append("}");
}
- return sb.append(_con.print(new SB()));
+ return sb.append(_con==null ? "---" : _con.print(new SB()));
}
@Override public boolean isConst() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index 0d49d025..922276d4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -40,7 +40,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
// Wider mask to store both GPRs and FPRs
@Override public RegMask regmap(int i) {
// 0 - ctrl
- // 1 - memory
+ 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
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
index fce8c499..bdd851ec 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
@@ -1,12 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.type.TypeInteger;
public class AddIRISC extends ImmRISC {
- AddIRISC( Node add, int imm ) { super(add,imm); }
+ // Used to inst-selection as a direct match against an ideal Add/Sub
+ AddIRISC( Node add, int imm, boolean pop ) { super(add,imm,pop); }
+ @Override public String op() { return "addi"; }
+ @Override public String glabel() { return "+"; }
@Override int opcode() { return riscv.I_TYPE; }
@Override int func3() {return 0;}
- @Override public String glabel() { return "+"; }
- @Override public String op() { return "addi"; }
+ @Override public AddIRISC copy() { return new AddIRISC(this,_imm12,false); }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 825d9449..4e73aeab 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -3,7 +3,7 @@ package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-
+import com.seaofnodes.simple.type.TypeInteger;
import java.util.BitSet;
abstract public class ImmRISC extends MachConcreteNode implements MachNode {
@@ -11,15 +11,27 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode {
ImmRISC( Node add, int imm12, boolean pop ) {
super(add);
_imm12 = imm12;
+ // If pop, we are moving from a ideal Node to MachNode; the ideal Node
+ // inputs got copied here, but we are absorbing the immediate into the
+ // MachNode and so do not want the constant input.
if( pop ) _inputs.pop();
+ // if NOT pop, we are the 2nd-half of a 2-part expansion, reset the
+ // input edges to no-control
+ else { _inputs.set(0,null); _inputs.setX(1,add); }
}
ImmRISC( Node add, int imm12 ) { this(add,imm12,true); }
@Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
+ @Override public boolean isClone() {
+ // Allow cloning of the 2nd half of a 2-part constant; this might
+ // trigger cloning the first part also.
+ return in(1) instanceof LUI || in(1) instanceof AUIPC;
+ }
@Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits
in(1)._print0(sb.append("( "), visited);
- return sb.append(String.format(" %s #%d )",glabel(),_imm12));
+ return sb.append(String.format(" %s #%d )",glabel(),imm12));
}
abstract int opcode();
@@ -35,6 +47,9 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode {
// General form: "addi rd = rs1 + imm"
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(_imm12);
+ int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(imm12);
+ if( in(1) instanceof LUI lui )
+ sb.p(" // #").hex4((int)(((TypeInteger)lui._con).value()) + imm12);
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
index 38e7e4b1..df0d6b4b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
@@ -8,14 +8,14 @@ import com.seaofnodes.simple.type.TypeInteger;
// Load upper 20bits.
public class LUI extends ConstantNode implements MachNode {
- LUI( TypeInteger ti ) {
- super(ti);
- assert riscv.imm20Exact(ti);
+ LUI( int imm20 ) {
+ super(TypeInteger.constant(imm20));
+ assert riscv.imm20Exact((TypeInteger)_con);
}
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return riscv.WMASK; }
@Override public boolean isClone() { return true; }
- @Override public LUI copy() { return new LUI((TypeInteger)_con); }
+ @Override public LUI copy() { return new LUI((int)((TypeInteger)_con).value()); }
@Override public String op() { return "lui"; }
@Override public void encoding( Encoding enc ) {
long x = ((TypeInteger)_con).value();
@@ -27,6 +27,6 @@ public class LUI extends ConstantNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
String reg = code.reg(this);
- _con.print(sb.p(reg).p(" = #"));
+ sb.p(reg).p(" = #").hex4((int)(((TypeInteger)_con).value()));
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
index 9b6eb98e..7002e0a8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
@@ -32,8 +32,8 @@ public class NewRISC extends NewNode implements MachNode {
enc.add4(body);
}
- // General form: "alloc #bytes"
+ // General form: "alloc #bytes PC"
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(size()));
+ sb.p(code.reg(size())).p(" ").p(code.reg(in(nIns()-1)));
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
index b78eac1f..383e37b5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
@@ -23,7 +23,7 @@ public class StoreRISC extends MemOpRISC {
@Override public String op() { return "st"+_sz; }
@Override public RegMask regmap(int i) {
// 0 - ctrl
- // 1 - mem
+ if( i==1 ) return null; // mem
if( i==2 ) return riscv.RMASK; // ptr
// 2 - index
if( i==4 ) return riscv.MEM_MASK; // Wide mask to store GPR and FPR
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index 16b09172..fcea5e28 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -202,24 +202,6 @@ public class riscv extends Machine {
};
}
- public static void push_4_bytes(int value, ByteArrayOutputStream bytes) { throw Utils.TODO(); }
-
-// public static void print_as_hex(ByteArrayOutputStream outputStream) {
-// StringBuilder hexString = new StringBuilder();
-// for (byte b : outputStream.toByteArray()) {
-// hexString.append(String.format("%02X", b)); // Format as uppercase hex without space
-// }
-// System.out.println(hexString.toString());
-// }
-
-// // rs1 - rs2
-// public static int r_source(int rs1, int rs2) {
-// return (rs2 << 4) | rs1;
-// }
-// public static int r_func7(int f) {
-// return f & 7;
-// }
-
static RegMask callInMask( TypeFunPtr tfp, int idx ) {
if( idx==0 ) return RPC_MASK;
if( idx==1 ) return null;
@@ -363,7 +345,7 @@ public class riscv extends Machine {
private Node add(AddNode add) {
if( add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti) )
- return new AddIRISC(add, (int)ti.value());
+ return new AddIRISC(add, (int)ti.value(),true);
return new AddRISC(add);
}
@@ -427,13 +409,15 @@ public class riscv extends Machine {
return switch( con._con ) {
case TypeInteger ti -> {
if( imm12(ti) ) yield new IntRISC(con);
- if( imm20Exact(ti) ) yield new LUI(ti);
long x = ti.value();
- if( (x<<32)>>32 == x ) // Signed lower 32-bit immediate
+ if( imm20Exact(ti) ) yield new LUI((int)x);
+ if( (x<<32)>>32 == x ) { // Signed lower 32-bit immediate
// Here, the low 12 bits get sign-extended, which means if
// bit11 is set, the value is negative and lowers the LUI
// value. Add a bit 12 to compensate
- yield new AddIRISC(new LUI(((x>>11)&1)==1 ? TypeInteger.constant(x+0x1000) : ti), (int)(x & 0xFFF));
+ if( ((x>>11)&1)==1 ) x += 0x1000;
+ yield new AddIRISC(new LUI((int)(x & ~0xFFF)), (int)(x & 0xFFF),false);
+ }
// Need more complex sequence for larger constants... or a load
// from a constant pool, which does not need an extra register
throw Utils.TODO();
@@ -489,7 +473,7 @@ public class riscv extends Machine {
private Node sub(SubNode sub) {
return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti)
- ? new AddIRISC(sub, (int)(-ti.value()))
+ ? new AddIRISC(sub, (int)(-ti.value()),true)
: new SubRISC(sub);
}
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 77d891a2..55a45a32 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -48,44 +48,32 @@ public abstract class ASMPrinter {
if( bb instanceof CallNode ) return iadr;
final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
- // Count Phis
- int nPhi=0;
- for( ; nPhi<bb.nOuts(); nPhi++ )
- if( !(bb.out(nPhi) instanceof PhiNode) )
- break;
-
- if( nPhi>0 ) {
- // Post- RegAlloc phi prints all on one line
+ boolean once=false;
+ for( Node n : bb.outs() ) {
+ if( !(n instanceof PhiNode phi) ) continue;
+ if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
+ // Post-RegAlloc phi prints all on one line
if( postAlloc ) {
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ");
- for( int i=0; i<nPhi; i++ ) {
- PhiNode phi = (PhiNode)bb.out(i);
- if( !(phi._type instanceof TypeMem || phi._type instanceof TypeRPC) ) // Nothing for the hidden ones
- sb.p(phi._label).p(':').p(code.reg(phi)).p(',');
- }
- sb.unchar().nl();
-
+ if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); }
+ sb.p(phi._label).p(':').p(code.reg(phi)).p(',');
} else {
- // Pre- RegAlloc phi prints one line per
- for( int j=0; j<nPhi; j++ ) {
- PhiNode phi = (PhiNode)bb.out(j);
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ");
- sb.p(code.reg(phi));
- if( !(phi instanceof ParmNode) ) {
- sb.p(" = phi( ");
- for( int i=1; i<phi.nIns(); i++ )
- sb.p("N").p(phi.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
+ // Pre-RegAlloc phi prints one line per
+ sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi));
+ if( phi.getClass() == PhiNode.class ) {
+ sb.p(" = phi( ");
+ for( int i=1; i<phi.nIns(); i++ )
+ sb.p("N").p(phi.in(i)._nid).p(",");
+ sb.unchar().p(" )");
}
+ sb.nl();
}
}
+ if( once ) sb.unchar().nl();
// All the non-phis
- for( int i=nPhi; i<bb.nOuts(); i++ )
- iadr = doInst(iadr, sb,code, cfgidx, bb.out(i),postAlloc );
+ for( int i=0; i<bb.nOuts(); i++ )
+ if( !(bb.out(i) instanceof PhiNode) )
+ iadr = doInst(iadr, sb,code, cfgidx, bb.out(i),postAlloc );
return iadr;
}
@@ -106,7 +94,7 @@ public abstract class ASMPrinter {
break; // Has code in the block, need to jump around
// No code in the block, can fall through it
}
- sb.hex4(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
+ sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
return iadr;
}
@@ -120,14 +108,14 @@ public abstract class ASMPrinter {
// ADDR ENCODING Op--- dst = src op src // Comment
// 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex4(iadr);
+ sb.hex2(iadr);
sb.p(" ");
// Encoding
if( code._encoding != null ) {
int size = code._encoding._opLen[n._nid];
for( int i=0; i<size; i++ )
- sb.hex2(code._encoding._bits.buf()[iadr++]);
+ sb.hex1(code._encoding._bits.buf()[iadr++]);
for( int i=size*2; i<encWidth; i++ )
sb.p(" ");
} else
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 7f5cabc4..a18822c2 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -10,6 +10,7 @@ import static org.junit.Assert.*;
public class Chapter20Test {
+ //-3834621514626535010L
@Test
public void testJig() {
CodeGen code = new CodeGen("return 0;");
@@ -23,7 +24,6 @@ public class Chapter20Test {
code.parse().opto().typeCheck().instSelect(PORTS,cpu,os).GCM().localSched().regAlloc();
int delta = spills>>3;
if( delta==0 ) delta = 1;
- code.asm();
assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);
if( stop != null )
assertEquals(stop, code._stop.toString());