summaryrefslogtreecommitdiff
path: root/chapter23/src/main
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-09-28 15:42:57 -0700
committerCliff Click <cliffc@acm.org>2026-09-28 15:42:57 -0700
commit75390f477ac7d4568ac02f97358d146ff9879d6e (patch)
treea6dc2226357ecb03359414b51f3de87034892aca /chapter23/src/main
parent586c8f65f2d0c0e1f73aadd0aa8d850aa653bddd (diff)
downloadSimple-75390f477ac7d4568ac02f97358d146ff9879d6e.tar.gz
Simple-75390f477ac7d4568ac02f97358d146ff9879d6e.zip
Backport FunPtr
Helps keep functions alive via ptr only (no calls). A few RISC 5 TFP encoding fixes.
Diffstat (limited to 'chapter23/src/main')
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/Parser.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java4
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java1
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java4
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/FunNode.java10
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java15
7 files changed, 36 insertions, 13 deletions
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/Parser.java b/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
index be5c8932..5b3f4d1a 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
@@ -1618,7 +1618,7 @@ public class Parser {
// Make a concrete function type, with a fidx
TypeFunPtr tfp = _code.makeFun(TypeFunPtr.make(false,false,ts.asAry(),Type.BOTTOM));
ReturnNode ret = parseFunctionBody(tfp,loc,ids.asAry());
- return con(ret._fun.sig());
+ return new FunPtrNode(ret._fun.sig(),ret).peephole();
}
/**
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index adfefae5..50490689 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -194,7 +194,7 @@ public class CodeGen {
for( int i=0; i<_start.nOuts(); i++ ) {
Node use = _start.out(i);
if( use instanceof FunNode fun &&
- fun.nIns()==2 && fun.in(1)==_start && fun != main &&
+ fun.nIns()==2 && fun.in(1)==_start && fun != main && !fun.hasPtr() &&
(fun._name==null || fun._name.startsWith("sys.")) ) {
add(fun).setDef(1,Parser.XCTRL);
addAll(fun._outputs);
@@ -353,6 +353,8 @@ public class CodeGen {
// Produce a machine node from n; map it to flag as done so stops cycles.
map.put(n, x=_mach.instSelect(n) );
+ // Stop retains the callable body. Its lifetime edge is not a machine operand.
+ if( n instanceof FunPtrNode ) x._inputs.pop();
// Walk machine op and replace inputs with mapped inputs
for( int i=0; i < x.nIns(); i++ )
x._inputs.set(i, _instSelect(x.in(i),map) );
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
index 8f9e2981..b6267600 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
@@ -222,6 +222,7 @@ public class ElfFile {
i++;
int end = _code._encoding._opStart[ret._nid] + _code._encoding._opLen[ret._nid];
+ if( fun._name==null ) continue; // Anonymous addresses are relocated within .text.
Symbol func = new Symbol(fun._name, text._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC);
func._value = _code._encoding._opStart[fun._nid];
func._size = end - func._value;
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 8fd0e61e..0d7c0964 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -27,6 +27,10 @@ public class ConstantNode extends Node {
public static Node make( Type type ) {
if( type==Type. CONTROL ) return new CtrlNode();
if( type==Type.XCONTROL ) return new XCtrlNode();
+ if( type instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) {
+ FunNode fun = CodeGen.CODE.link(tfp);
+ if( fun!=null && !fun.isDead() ) return new FunPtrNode(tfp,fun.ret());
+ }
return new ConstantNode(type);
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/FunNode.java
index 88f5dc18..e7d6c3a6 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/FunNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/FunNode.java
@@ -61,6 +61,16 @@ public class FunNode extends RegionNode {
public void setRet(ReturnNode ret) { _ret=ret; }
public ReturnNode ret() { assert _ret!=null; return _ret; }
+ // Direct calls are known; any other use of an address may have unknown callers.
+ public boolean hasPtr() {
+ for( Node use : ret()._outputs )
+ if( use instanceof FunPtrNode )
+ for( Node user : use._outputs )
+ if( !(user instanceof CallNode call) || call.fptr()!=use ||
+ call._inputs.find(use)!=call.nIns()-1 ) return true;
+ return false;
+ }
+
// Signature can improve over time
public TypeFunPtr sig() { return _sig; }
public void setSig( TypeFunPtr sig ) {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
new file mode 100644
index 00000000..7f32698e
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
@@ -0,0 +1,13 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.type.TypeFunPtr;
+
+// A function address keeps its body alive, even without a linked Call.
+public class FunPtrNode extends ConstantNode {
+ public FunPtrNode(TypeFunPtr tfp, ReturnNode ret) {
+ super(tfp);
+ addDef(ret);
+ }
+ public ReturnNode ret() { return (ReturnNode)in(1); }
+ @Override public String uniqueName() { return "FunPtr_"+_nid; }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
index 7e057507..db140304 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
@@ -26,22 +26,15 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize {
enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0));
}
- @Override public byte encSize(int delta) {
- if( -(1L<<11) <= delta && delta < (1L<<11) ) return 4;
- throw Utils.TODO();
- }
+ @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 rpc = enc.reg(this);
if( opLen==8 ) {
- // AUIPC (upper 20 bits)
- // opstart of add
- int next = opStart + opLen;
- enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta>>12));
- // addi(low 12 bits)
- enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF));
- // addi
+ // ADDI sign-extends its low 12 bits, so round the AUIPC high part.
+ enc.patch4(opStart ,riscv.u_type(riscv.OP_AUIPC, rpc, (delta+0x800)>>12));
+ enc.patch4(opStart+4,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF));
} else {
// should not happen as one instruction is 4 byte, and TFP arm encodes 2.
throw Utils.TODO();