Skip to content

Commit 4e7734b

Browse files
authored
feat: add an alwaysInline builtin (#2895)
1 parent 513acc8 commit 4e7734b

File tree

8 files changed

+397
-7
lines changed

8 files changed

+397
-7
lines changed

src/builtins.ts

+19
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ export namespace BuiltinNames {
191191
export const assert = "~lib/builtins/assert";
192192
export const call_indirect = "~lib/builtins/call_indirect";
193193
export const unchecked = "~lib/builtins/unchecked";
194+
export const inline_always = "~lib/builtins/inline.always";
194195
export const instantiate = "~lib/builtins/instantiate";
195196
export const idof = "~lib/builtins/idof";
196197

@@ -3611,6 +3612,24 @@ function builtin_unchecked(ctx: BuiltinFunctionContext): ExpressionRef {
36113612
}
36123613
builtinFunctions.set(BuiltinNames.unchecked, builtin_unchecked);
36133614

3615+
// inline.always(expr: *) -> *
3616+
function builtin_inline_always(ctx: BuiltinFunctionContext): ExpressionRef {
3617+
let compiler = ctx.compiler;
3618+
let module = compiler.module;
3619+
if (
3620+
checkTypeAbsent(ctx) |
3621+
checkArgsRequired(ctx, 1)
3622+
) return module.unreachable();
3623+
let flow = compiler.currentFlow;
3624+
let alreadyInline = flow.is(FlowFlags.InlineContext);
3625+
if (!alreadyInline) flow.set(FlowFlags.InlineContext);
3626+
// eliminate unnecessary tees by preferring contextualType(=void)
3627+
let expr = compiler.compileExpression(ctx.operands[0], ctx.contextualType);
3628+
if (!alreadyInline) flow.unset(FlowFlags.InlineContext);
3629+
return expr;
3630+
}
3631+
builtinFunctions.set(BuiltinNames.inline_always, builtin_inline_always);
3632+
36143633
// call_indirect<T?>(index: u32, ...args: *[]) -> T
36153634
function builtin_call_indirect(ctx: BuiltinFunctionContext): ExpressionRef {
36163635
let compiler = ctx.compiler;

src/compiler.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -6281,7 +6281,8 @@ export class Compiler extends DiagnosticEmitter {
62816281
}
62826282

62836283
// Inline if explicitly requested
6284-
if (instance.hasDecorator(DecoratorFlags.Inline) && (!instance.is(CommonFlags.Overridden) || reportNode.isAccessOnSuper)) {
6284+
let inlineRequested = instance.hasDecorator(DecoratorFlags.Inline) || this.currentFlow.is(FlowFlags.InlineContext);
6285+
if (inlineRequested && (!instance.is(CommonFlags.Overridden) || reportNode.isAccessOnSuper)) {
62856286
assert(!instance.is(CommonFlags.Stub)); // doesn't make sense
62866287
let inlineStack = this.inlineStack;
62876288
if (inlineStack.includes(instance)) {

src/flow.ts

+2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ export const enum FlowFlags {
146146
UncheckedContext = 1 << 15,
147147
/** This is a flow compiling a constructor parameter. */
148148
CtorParamContext = 1 << 16,
149+
/** This is a flow where all function calls are inlined if possible. */
150+
InlineContext = 1 << 17,
149151

150152
// masks
151153

std/assembly/builtins.ts

+6
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ export declare function assert<T>(isTrueish: T, message?: string): T;
202202
@unsafe @builtin
203203
export declare function unchecked<T>(expr: T): T;
204204

205+
export namespace inline {
206+
// @ts-ignore: decorator
207+
@unsafe @builtin
208+
export declare function always<T>(expr: T): T;
209+
}
210+
205211
// @ts-ignore: decorator
206212
@unsafe @builtin
207213
export declare function call_indirect<T>(index: u32, ...args: auto[]): T;

std/assembly/index.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2693,6 +2693,10 @@ declare function final(constructor: Constructor): void;
26932693

26942694
/** Annotates a method, function or constant global as always inlined. */
26952695
declare function inline(...args: any[]): any;
2696+
declare namespace inline {
2697+
/** Explicitly requests inlined function calls on the provided expression wherever possible. */
2698+
declare function always<T>(value: T): T;
2699+
}
26962700

26972701
/** Annotates a method, function or constant global as unsafe. */
26982702
declare function unsafe(...args: any[]): any;

tests/compiler/inlining.debug.wat

+192-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
(type $4 (func (param i32 i32) (result i32)))
77
(type $5 (func (result i32)))
88
(type $6 (func (param i32 i32 i32)))
9-
(type $7 (func (param i32 i32 i32 i32)))
10-
(type $8 (func (param i32 i32 i64) (result i32)))
9+
(type $7 (func (param i32 i32 i32) (result f64)))
10+
(type $8 (func (param i32 i32 i32 i32)))
11+
(type $9 (func (param i32 i32 i64) (result i32)))
12+
(type $10 (func (param f64) (result f64)))
1113
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
1214
(global $inlining/constantGlobal i32 (i32.const 1))
1315
(global $~argumentsLength (mut i32) (i32.const 0))
@@ -44,6 +46,8 @@
4446
(table $0 2 2 funcref)
4547
(elem $0 (i32.const 1) $inlining/func_fe~anonymous|0)
4648
(export "test" (func $inlining/test))
49+
(export "foo" (func $inlining/foo))
50+
(export "bar" (func $inlining/bar))
4751
(export "memory" (memory $0))
4852
(start $~start)
4953
(func $inlining/test (result i32)
@@ -2573,6 +2577,192 @@
25732577
global.set $~lib/rt/itcms/fromSpace
25742578
call $inlining/test_ctor
25752579
)
2580+
(func $~lib/math/NativeMath.cbrt (param $x f64) (result f64)
2581+
(local $u i64)
2582+
(local $hx i32)
2583+
(local $t f64)
2584+
(local $r f64)
2585+
(local $s f64)
2586+
local.get $x
2587+
i64.reinterpret_f64
2588+
local.set $u
2589+
local.get $u
2590+
i64.const 32
2591+
i64.shr_u
2592+
i32.wrap_i64
2593+
i32.const 2147483647
2594+
i32.and
2595+
local.set $hx
2596+
local.get $hx
2597+
i32.const 2146435072
2598+
i32.ge_u
2599+
if
2600+
local.get $x
2601+
local.get $x
2602+
f64.add
2603+
return
2604+
end
2605+
local.get $hx
2606+
i32.const 1048576
2607+
i32.lt_u
2608+
if
2609+
local.get $x
2610+
f64.const 18014398509481984
2611+
f64.mul
2612+
i64.reinterpret_f64
2613+
local.set $u
2614+
local.get $u
2615+
i64.const 32
2616+
i64.shr_u
2617+
i32.wrap_i64
2618+
i32.const 2147483647
2619+
i32.and
2620+
local.set $hx
2621+
local.get $hx
2622+
i32.const 0
2623+
i32.eq
2624+
if
2625+
local.get $x
2626+
return
2627+
end
2628+
local.get $hx
2629+
i32.const 3
2630+
i32.div_u
2631+
i32.const 696219795
2632+
i32.add
2633+
local.set $hx
2634+
else
2635+
local.get $hx
2636+
i32.const 3
2637+
i32.div_u
2638+
i32.const 715094163
2639+
i32.add
2640+
local.set $hx
2641+
end
2642+
local.get $u
2643+
i64.const 1
2644+
i64.const 63
2645+
i64.shl
2646+
i64.and
2647+
local.set $u
2648+
local.get $u
2649+
local.get $hx
2650+
i64.extend_i32_u
2651+
i64.const 32
2652+
i64.shl
2653+
i64.or
2654+
local.set $u
2655+
local.get $u
2656+
f64.reinterpret_i64
2657+
local.set $t
2658+
local.get $t
2659+
local.get $t
2660+
f64.mul
2661+
local.get $t
2662+
local.get $x
2663+
f64.div
2664+
f64.mul
2665+
local.set $r
2666+
local.get $t
2667+
f64.const 1.87595182427177
2668+
local.get $r
2669+
f64.const -1.8849797954337717
2670+
local.get $r
2671+
f64.const 1.6214297201053545
2672+
f64.mul
2673+
f64.add
2674+
f64.mul
2675+
f64.add
2676+
local.get $r
2677+
local.get $r
2678+
f64.mul
2679+
local.get $r
2680+
f64.mul
2681+
f64.const -0.758397934778766
2682+
local.get $r
2683+
f64.const 0.14599619288661245
2684+
f64.mul
2685+
f64.add
2686+
f64.mul
2687+
f64.add
2688+
f64.mul
2689+
local.set $t
2690+
local.get $t
2691+
i64.reinterpret_f64
2692+
i64.const 2147483648
2693+
i64.add
2694+
i64.const -1073741824
2695+
i64.and
2696+
f64.reinterpret_i64
2697+
local.set $t
2698+
local.get $t
2699+
local.get $t
2700+
f64.mul
2701+
local.set $s
2702+
local.get $x
2703+
local.get $s
2704+
f64.div
2705+
local.set $r
2706+
local.get $r
2707+
local.get $t
2708+
f64.sub
2709+
f64.const 2
2710+
local.get $t
2711+
f64.mul
2712+
local.get $r
2713+
f64.add
2714+
f64.div
2715+
local.set $r
2716+
local.get $t
2717+
local.get $t
2718+
local.get $r
2719+
f64.mul
2720+
f64.add
2721+
local.set $t
2722+
local.get $t
2723+
return
2724+
)
2725+
(func $inlining/foo (param $a i32) (param $b i32) (param $c i32) (result f64)
2726+
local.get $a
2727+
f64.convert_i32_s
2728+
local.get $b
2729+
f64.convert_i32_s
2730+
call $~lib/math/NativeMath.cbrt
2731+
f64.mul
2732+
local.get $c
2733+
f64.convert_i32_s
2734+
f64.add
2735+
return
2736+
)
2737+
(func $inlining/bar (param $a i32) (param $b i32) (param $c i32) (result f64)
2738+
(local $a|3 i32)
2739+
(local $b|4 i32)
2740+
(local $c|5 i32)
2741+
block $inlining/foo|inlined.0 (result f64)
2742+
local.get $a
2743+
local.set $a|3
2744+
local.get $b
2745+
local.set $b|4
2746+
local.get $c
2747+
local.set $c|5
2748+
local.get $a|3
2749+
f64.convert_i32_s
2750+
local.get $b|4
2751+
f64.convert_i32_s
2752+
call $~lib/math/NativeMath.cbrt
2753+
f64.mul
2754+
local.get $c|5
2755+
f64.convert_i32_s
2756+
f64.add
2757+
br $inlining/foo|inlined.0
2758+
end
2759+
local.get $b
2760+
local.get $a
2761+
local.get $c
2762+
call $inlining/foo
2763+
f64.div
2764+
return
2765+
)
25762766
(func $~lib/rt/__visit_globals (param $0 i32)
25772767
(local $1 i32)
25782768
i32.const 304

0 commit comments

Comments
 (0)