diff options
| author | Cliff Click <cliffc@acm.org> | 2026-09-28 15:42:57 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-09-28 15:42:57 -0700 |
| commit | 75390f477ac7d4568ac02f97358d146ff9879d6e (patch) | |
| tree | a6dc2226357ecb03359414b51f3de87034892aca /chapter22/src/main/java/com | |
| parent | 586c8f65f2d0c0e1f73aadd0aa8d850aa653bddd (diff) | |
| download | Simple-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 'chapter22/src/main/java/com')
8 files changed, 38 insertions, 15 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java index 087fd1fd..8132f782 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java @@ -1457,7 +1457,7 @@ public class Parser { // Make a concrete function type, with a fidx TypeFunPtr tfp = _code.makeFun(TypeTuple.make(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/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index 0c00b9c6..7c884b49 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -188,7 +188,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); @@ -331,6 +331,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/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java index 0eaaae7b..88af3f27 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java @@ -221,6 +221,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/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java index 1b4b619a..f37da4f3 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java @@ -75,10 +75,10 @@ public class CallEndNode extends CFGNode implements MultiNode { assert fun.in(1) instanceof StartNode && fun.in(2)==call; // Disallow self-recursive inlining (loop unrolling by another name) CFGNode idom = call; - while( !(idom instanceof FunNode) ) + while( idom!=null && !(idom instanceof FunNode) ) idom = idom.idom(); // Inline? - if( idom != fun ) { + if( idom != null && idom != fun ) { // Trivial inline: rewrite _folding = true; // Rewrite Fun so the normal RegionNode ideal collapses diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 9785855b..60aa40c4 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -32,6 +32,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/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java index 9afbf77e..5f67f859 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java @@ -60,6 +60,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/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java new file mode 100644 index 00000000..7f32698e --- /dev/null +++ b/chapter22/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/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index 15be82bc..1d1f30e9 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -25,22 +25,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(); |
