Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
381 changes: 222 additions & 159 deletions src/engine/compiler/SinglePassCompiler.v3

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/engine/x86-64/X86_64SinglePassCompiler.v3
Original file line number Diff line number Diff line change
Expand Up @@ -1535,7 +1535,8 @@ component X86_64Spc {
return addr;
}
def estimateCodeSizeFor(decl: FuncDecl) -> int {
return 60 + decl.orig_bytecode.length * 20; // TODO: huge overestimate
// TODO: very imprecise estimate
return 60 + decl.orig_bytecode.length * 20 * (4 << byte.view(SpcTuning.maxInlineDepth));
}
private def lazyCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) {
// The global stub simply consults the execution strategy.
Expand Down
32 changes: 28 additions & 4 deletions src/util/Whamm.v3
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,9 @@ component Whamm {
class WhammProbe(func: Function, sig: Array<WhammArg>) extends Probe {
var trampoline: TargetCode;
// properties set by the spc to make inlining optimization decisions.
var inline_heuristic_checked = false;
var spc_inline_func = false;
var spc_swap_instance = false;
var spc_swap_membase = false;
var swap_checked = false;
var swap_instance = false;
var swap_membase = false;

private def args = if(sig.length == 0, Values.NONE, Array<Value>.new(sig.length));

Expand All @@ -203,6 +202,31 @@ class WhammProbe(func: Function, sig: Array<WhammArg>) extends Probe {
}
return ProbeAction.Continue;
}

// If function is to be inlined, check to see if instance or mem0_base need to be swapped.
def checkSwap() {
if (swap_checked) return;
var bi = BytecodeIterator.new().reset(WasmFunction.!(func).decl);
while (bi.more()) {
var op = bi.current();
match (op) {
// These opcodes require swapping the instance.
THROW, CALL, CALL_INDIRECT, MEMORY_INIT, MEMORY_SIZE, MEMORY_GROW, MEMORY_COPY, MEMORY_FILL, REF_FUNC, DATA_DROP,
ELEM_DROP, TABLE_INIT, TABLE_SIZE, TABLE_COPY, TABLE_GROW, GLOBAL_SET, GLOBAL_GET, TABLE_SET, TABLE_GET => swap_instance = true;
// Load/store opcodes require either the memory base or the instance.
I32_STORE, I64_STORE, F32_STORE, F64_STORE, I32_STORE8, I32_STORE16, I64_STORE8, I64_STORE16, I64_STORE32,
V128_STORE, I32_LOAD, I64_LOAD, F32_LOAD, F64_LOAD, I32_LOAD8_S, I32_LOAD8_U, I32_LOAD16_S, I32_LOAD16_U,
I64_LOAD8_S, I64_LOAD8_U, I64_LOAD16_S, I64_LOAD16_U, I64_LOAD32_S, I64_LOAD32_U, V128_LOAD => {
var memarg = bi.immptr().read_MemArg();
if (memarg.memory_index == 0) swap_membase = true;
else swap_instance = true;
}
_ => ;
}
bi.next();
}
swap_checked = true;
}
}

def parseParam0(r: TextReader) -> WhammParam {
Expand Down
3 changes: 0 additions & 3 deletions test/inline/failures.x86-64-linux

This file was deleted.

1 change: 1 addition & 0 deletions test/inline/failures.x86-64-linux.dyn
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
inline_test_arithmetic.wasm
inline_test_locals_control.wasm
inline_test_nesting.wasm
inline_test_return.wasm

Binary file added test/inline/inline_test_return.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions test/inline/inline_test_return.wasm.exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
1 change: 1 addition & 0 deletions test/inline/inline_test_return.wasm.flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--metrics=spc*calls --inline-max-depth=1
4 changes: 4 additions & 0 deletions test/inline/inline_test_return.wasm.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
spc:static_calls : 6 calls
spc:static_inlined_calls : 6 calls
spc:dynamic_calls : 6 calls
spc:dynamic_inlined_calls : 6 calls
97 changes: 97 additions & 0 deletions test/inline/inline_test_return.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
;; Test inlined functions with explicit RETURN, including nested control flow
;; and paths where extra values are on the stack at the time of return.
(module
;; Two levels of nested ifs; in the early-return path, 2*a is an extra value
;; on the value stack below the returned a+b.
(func $weighted (param i32) (param i32) (result i32)
block (result i32)
local.get 0
i32.const 2
i32.mul ;; [2a] -- extra below when early return fires
block
local.get 0
i32.const 0
i32.gt_s
if
local.get 1
i32.const 0
i32.gt_s
if
;; both positive: return a+b; 2a is extra on stack
local.get 0
local.get 1
i32.add
return
end
end
end
local.get 1
i32.add ;; fallthrough: 2a+b
end
)

;; Clamp x to [lo, hi]; two levels of nesting, returns on multiple paths.
(func $clamp (param i32) (param i32) (param i32) (result i32)
local.get 0
local.get 1
i32.lt_s
if
local.get 1
return
end
local.get 0
local.get 2
i32.gt_s
if
local.get 2
return
end
local.get 0
)

(func (export "main") (result i32)
i32.const 3
i32.const 4
call $weighted
i32.const 7 ;; both positive: 3+4=7
i32.ne

i32.const 3
i32.const -1
call $weighted
i32.const 5 ;; b<=0: 2*3+(-1)=5
i32.ne
i32.or

i32.const -1
i32.const 4
call $weighted
i32.const 2 ;; a<=0: 2*(-1)+4=2
i32.ne
i32.or

i32.const 5
i32.const 0
i32.const 10
call $clamp
i32.const 5
i32.ne
i32.or

i32.const -3
i32.const 0
i32.const 10
call $clamp
i32.const 0
i32.ne
i32.or

i32.const 15
i32.const 0
i32.const 10
call $clamp
i32.const 10
i32.ne
i32.or
)
)
Loading