Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bf3a9e1
[WIP] Add regular inlining options, heuristic, emit inlined calls (wr…
matthew-mojira Feb 10, 2026
1873013
Track chains of inlined calls; on trap, materialize frames for the st…
matthew-mojira Feb 10, 2026
c0ae29e
Fix fixing state when inlined function contains unreachable (maybe not)
matthew-mojira Feb 11, 2026
3ad61ef
Add SpcFrame (frame stack) to SpcState
matthew-mojira Feb 12, 2026
9d3a511
Update disallowed instructions and emit frames during out-calls
matthew-mojira Feb 13, 2026
2ace955
Add InlineFrameStub for proper stack walking
matthew-mojira Feb 13, 2026
c7a0043
Remove swap_membase and swap_instance from regular inlining
matthew-mojira Feb 16, 2026
30b71ea
Add unrefRegs before emitting stack reconstruction
matthew-mojira Feb 16, 2026
f9d781c
[WIP] Support control flow instructions, add implicit block for inlin…
matthew-mojira Feb 16, 2026
f7b1566
Fix SPC bug
matthew-mojira Feb 16, 2026
b3fa52e
Reconstruct stack frames around probes
matthew-mojira Feb 16, 2026
ba368f7
Fix inlining whamm probes
matthew-mojira Feb 17, 2026
15ed9c9
Modify Whamm inlining to use regular inlining logic
matthew-mojira Feb 17, 2026
92e1f62
Increase inlining pressure and code size estimate
matthew-mojira Feb 17, 2026
5d6f9be
[temp] add failing test to expected failures
matthew-mojira Feb 17, 2026
4aab541
Always swap instance and membase for Whamm probe inlining
matthew-mojira Feb 18, 2026
da872b3
Add metrics to track inlining counts other various TODOs
matthew-mojira Feb 18, 2026
eb142b9
Allow gc instructions, simplify size estimate and increase inlining d…
matthew-mojira Feb 18, 2026
f0f9988
Reduce inlining depth to 3
matthew-mojira Feb 18, 2026
c3f4d42
Add CLI for inline-specific options
matthew-mojira Feb 19, 2026
fda474e
Add inline tests
matthew-mojira Feb 20, 2026
d21635f
Remove extra flags files
matthew-mojira Feb 20, 2026
d03cc74
Add inline context to masm, emit inline frames for hardware traps
matthew-mojira Mar 9, 2026
3ac9c58
Reconstruct stack frames for runtime calls that may trap
matthew-mojira Mar 9, 2026
7e68f5d
rename InlinedFrameStub to SpcInlinedFrame
matthew-mojira Mar 10, 2026
57efeb5
Refactor emitReconstructStackFrames
matthew-mojira Mar 10, 2026
0f0a8a3
Consolidate testing and skip inlining tests for non-spc targets
matthew-mojira Mar 10, 2026
cf68d23
Remove redundant inlining option
matthew-mojira Mar 10, 2026
58e616e
Fix inlining option with whamm probe inlining
matthew-mojira Mar 10, 2026
8697eda
Add static/dynamic inlining counts to metrics
matthew-mojira Mar 11, 2026
48f9b5b
Merge branch 'titzer:master' into spc-inline
matthew-mojira Mar 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/engine/Metrics.v3
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ component Metrics {
"Number of functions successfully compiled by single-pass compiler");
def spc_time_per_byte = r("spc:time_per_byte", spc_time_us, spc_in_bytes,
"Ratio of compile time per input bytecode byte");
def spc_static_calls = m("spc:static_calls", "calls", "Number of call instructions encountered by single-pass compiler");
def spc_static_inlined_calls = m("spc:static_inlined_calls", "calls", "Number of direct call sites inlined by single-pass compiler");
// XXX does not include inlined whamm probes, but does include inlining within a whamm inline
def spc_dynamic_calls = m("spc:dynamic_calls", "calls", "Number of call instructions executed at runtime");
def spc_dynamic_inlined_calls = m("spc:dynamic_inlined_calls", "calls", "Number of inlined call sites executed at runtime");
def spc_static_remat = m("spc:static_remat", "sites", "Number of sites where stack frame reconstruction is emitted");
def spc_dynamic_remat = m("spc:dynamic_remat", "sites", "Number of stack frame reconstructions executed at runtime");

// Metrics from executing wasm code.
def start_time_us = t("start:time_us", "Time taken to execute wasm module start function(s).");
Expand Down
5 changes: 4 additions & 1 deletion src/engine/Tuning.v3
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ component SpcTuning {
var intrinsifyOperandProbe = true; // recognize and optimize OperandProbes
var compileWhammModules = true; // compile whamm module, if possible
var intrinsifyWhammProbe = true; // recognize and optimize WhammProbes
var inlineSmallFunc = true; // inline small functions, currently only applicable for whamm probes
var inlineWhammProbe = true; // inline whamm probe functions
var maxInlineBytecodeSize = 100; // max bytecode size to inline
var maxInlineParams = 10; // max parameters to inline
var maxInlineDepth = 0; // max inlining nesting depth
def probeCallFreesRegs = true; // probe calls frees registers in abstract state
def runtimeCallFreesRegs = true; // runtime calls frees registers in abstract state
var intrinsifyMemoryProbes = true;
Expand Down
10 changes: 8 additions & 2 deletions src/engine/compiler/CompilerOptions.v3
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ component CompilerOptions {
.onSet(fun v => void(SpcTuning.intrinsifyMemoryProbes = v));
group.newBoolOption("compile-whamm-modules", true, "Compile whamm monitor modules before execution.")
.onSet(fun v => void(SpcTuning.compileWhammModules = v));
group.newBoolOption("inline-whamm-probes", true, "Inline small whamm probes.")
.onSet(fun v => void(SpcTuning.inlineSmallFunc = v));
group.newBoolOption("inline-whamm-probes", true, "Inline whamm probes.")
.onSet(fun v => void(SpcTuning.inlineWhammProbe = v));
group.newIntOption("inline-max-bytecode-size", SpcTuning.maxInlineBytecodeSize, "Maximum number of bytecodes in a function that can be inlined.")
.onSet(fun v => void(SpcTuning.maxInlineBytecodeSize = v));
group.newIntOption("inline-max-params", SpcTuning.maxInlineParams, "Maximum number of parameters of a function that can be inlined.")
.onSet(fun v => void(SpcTuning.maxInlineParams = v));
group.newIntOption("inline-max-depth", SpcTuning.maxInlineDepth, "Maximum inlining nesting depth.")
.onSet(fun v => void(SpcTuning.maxInlineDepth = v));
}

def printHelp(out: TraceBuilder) {
Expand Down
16 changes: 14 additions & 2 deletions src/engine/compiler/MacroAssembler.v3
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ class MasmLabel(create_pos: int) {
class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) {
var unimplemented: void -> void; // function to call for unimplemented bytecodes
var trap_labels: Array<MasmLabel>; // maps TrapReason to a label
var source_locs: Vector<(int, int)>; // list of (offset, source_loc) pairs
var source_locs: Vector<(int, List<(int, int)>)>; // list of (offset, [(fid, pc)])
var inline_ctx: List<(int, int)>; // list of (fid, pc)
var source_loc: int = -1; // current source location, if any
var current_fid: int = -1; // current function id, if any

var newTrapLabel: TrapReason -> MasmLabel;
var embeddedRefOffsets: Vector<int>;
var offsets = Target.getOffsets();
Expand Down Expand Up @@ -80,7 +83,15 @@ class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) {
def recordSourceLoc(offset: int) {
if (source_loc < 0) return;
if (source_locs == null) source_locs = Vector.new();
source_locs.put(offset, source_loc);

source_locs.put(offset, List.new((current_fid, source_loc), inline_ctx));
}
def pushInlineContext(fid: int) {
inline_ctx = List.new((fid, source_loc), inline_ctx);
}
def popInlineContext() {
if (inline_ctx != null) // need more specific than null?
inline_ctx = inline_ctx.tail;
}
def at(src: int) -> this {
source_loc = src;
Expand Down Expand Up @@ -336,6 +347,7 @@ class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) {
def emit_call_runtime_Probe_instr();
def emit_call_runtime_getFrameAccessorMetaRef();
def emit_increment_CountProbe(tmp: Reg, probe: CountProbe, increment: u64);
def emit_inc_metric(metric: Metric);
def emit_call_OperandProbe_i_v_fire(probe: OperandProbe_i_v, value_reg: Reg);
def emit_call_MemoryReadProbe_fire(probe: MemoryReadProbe);
def emit_call_runtime_cast();
Expand Down
Loading
Loading