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

Lines changed: 19 additions & 0 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 192 additions & 2 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy