///|
pub fn external_helper_symbols(
symbols : @wasm_milkir.RuntimeSymbols,
) -> Map[String, String] {
{
"memory.grow": symbols.memory_grow,
"memory.size": symbols.memory_size,
"memory.fill": symbols.memory_fill,
"memory.copy": symbols.memory_copy,
"memory.init": symbols.memory_init,
"data.drop": symbols.data_drop,
"table.grow": symbols.table_grow,
"table.fill": symbols.table_fill,
"table.copy": symbols.table_copy,
"table.init": symbols.table_init,
"elem.drop": symbols.elem_drop,
"gc.ref_test": symbols.gc_ref_test,
"gc.ref_cast": symbols.gc_ref_cast,
"gc.struct_get": symbols.gc_struct_get,
"gc.struct_set": symbols.gc_struct_set,
"gc.array_get": symbols.gc_array_get,
"gc.array_set": symbols.gc_array_set,
"gc.array_len": symbols.gc_array_len,
"gc.array_fill": symbols.gc_array_fill,
"gc.array_copy": symbols.gc_array_copy,
"gc.array_new_data": symbols.gc_array_new_data,
"gc.array_new_elem": symbols.gc_array_new_elem,
"gc.array_init_data": symbols.gc_array_init_data,
"gc.array_init_elem": symbols.gc_array_init_elem,
"gc.type_check_subtype": symbols.gc_type_check_subtype,
"gc.register_struct_inline": symbols.gc_register_struct_inline,
"gc.register_array_inline": symbols.gc_register_array_inline,
"gc.alloc_struct_slow": symbols.gc_alloc_struct_slow,
"gc.alloc_array_from_values_slow": symbols.gc_alloc_array_from_values_slow,
"gc.alloc_array_slow": symbols.gc_alloc_array_slow,
"exception.try_begin": symbols.exception_try_begin,
"exception.try_end": symbols.exception_try_end,
"exception.throw": symbols.exception_throw,
"exception.throw_tag": symbols.exception_throw_tag,
"exception.throw_ref": symbols.exception_throw_ref,
"exception.delegate": symbols.exception_delegate,
"exception.get_tag": symbols.exception_get_tag,
"exception.get_value": symbols.exception_get_value,
"exception.get_value_count": symbols.exception_get_value_count,
"exception.sigsetjmp": symbols.exception_sigsetjmp,
"exception.spill_locals": symbols.exception_spill_locals,
"exception.get_spilled_local": symbols.exception_get_spilled_local,
}
}
///|
struct WasmLoweringOptions {
use_subtype_indirect_check : Bool
canonical_type_indices : Array[Int]
context_slots : WasmContextSlots
}
///|
fn WasmLoweringOptions::canonicalize_indirect_type_idx(
self : WasmLoweringOptions,
raw_type_idx : Int,
) -> Int {
// Keep raw indices when full subtype checks are enabled.
if self.use_subtype_indirect_check {
return raw_type_idx
}
if raw_type_idx >= 0 && raw_type_idx < self.canonical_type_indices.length() {
self.canonical_type_indices[raw_type_idx]
} else {
raw_type_idx
}
}
///|
fn lower_extension_with_options(
options : WasmLoweringOptions,
ctx : @lower.LoweringContext,
inst : @milkir.Inst,
block : @block.Block,
ext : @milkir.ExtOp,
) -> @lower.ExtensionLowerResult {
match @wasm_milkir.decode_or_abort(ext) {
StructNew(type_idx) =>
return Handled(lower_struct_new(ctx, inst, block, type_idx))
ArrayNewFixed(type_idx, len) =>
return Handled(lower_array_new_fixed(ctx, inst, block, type_idx, len))
LoadMemBase(memidx) =>
lower_load_mem_base(ctx, inst, block, memidx, options.context_slots)
WasmCall(func_idx) => lower_call(ctx, inst, block, func_idx)
WasmCallIndirect(type_idx, table_idx) =>
lower_call_indirect(ctx, inst, block, type_idx, table_idx, options)
CallRef(type_idx) => lower_call_ref(ctx, inst, block, type_idx)
ReturnCall(func_idx) => lower_return_call(ctx, inst, block, func_idx)
ReturnCallIndirect(type_idx, table_idx) =>
lower_return_call_indirect(ctx, inst, block, type_idx, table_idx, options)
ReturnCallRef(type_idx) => lower_return_call_ref(ctx, inst, block, type_idx)
GetFuncRef(func_idx) =>
lower_get_func_ref(ctx, inst, block, func_idx, options.context_slots)
I31New => lower_i31_new(ctx, inst, block)
I31GetS => lower_i31_get_s(ctx, inst, block)
I31GetU => lower_i31_get_u(ctx, inst, block)
AnyConvertExtern | ExternConvertAny => lower_gc_convert(ctx, inst, block)
StructNewDefault(type_idx) =>
lower_struct_new_default(ctx, inst, block, type_idx)
StructGet(type_idx, field_idx) =>
lower_struct_get(ctx, inst, block, type_idx, field_idx)
StructGetS(type_idx, field_idx, byte_width) =>
lower_struct_get_s(ctx, inst, block, type_idx, field_idx, byte_width)
StructGetU(type_idx, field_idx, byte_width) =>
lower_struct_get_u(ctx, inst, block, type_idx, field_idx, byte_width)
StructSet(type_idx, field_idx) =>
lower_struct_set(ctx, inst, block, type_idx, field_idx)
ArrayNew(type_idx) => lower_array_new(ctx, inst, block, type_idx)
ArrayNewDefault(type_idx) =>
lower_array_new_default(ctx, inst, block, type_idx)
ArrayGet(type_idx) => lower_array_get(ctx, inst, block, type_idx)
ArrayGetS(type_idx, byte_width) =>
lower_array_get_s(ctx, inst, block, type_idx, byte_width)
ArrayGetU(type_idx, byte_width) =>
lower_array_get_u(ctx, inst, block, type_idx, byte_width)
ArraySet(type_idx) => lower_array_set(ctx, inst, block, type_idx)
ArrayLen => lower_array_len(ctx, inst, block)
ArrayFill(type_idx) => lower_array_fill(ctx, inst, block, type_idx)
ArrayCopy(dst_type, src_type) =>
lower_array_copy(ctx, inst, block, dst_type, src_type)
ArrayNewData(type_idx, data_idx) =>
lower_array_new_data(ctx, inst, block, type_idx, data_idx)
ArrayNewElem(type_idx, elem_idx) =>
lower_array_new_elem(ctx, inst, block, type_idx, elem_idx)
ArrayInitData(type_idx, data_idx) =>
lower_array_init_data(ctx, inst, block, type_idx, data_idx)
ArrayInitElem(type_idx, elem_idx) =>
lower_array_init_elem(ctx, inst, block, type_idx, elem_idx)
RefTest(type_idx, nullable) =>
lower_ref_test(ctx, inst, block, type_idx, nullable)
RefCast(type_idx, nullable) =>
lower_ref_cast(ctx, inst, block, type_idx, nullable)
RefEq => lower_ref_eq(ctx, inst, block)
Throw(tag_idx) => lower_throw(ctx, inst, block, tag_idx)
ThrowRef => lower_throw_ref(ctx, inst, block)
TryTableBegin(handler_id) =>
lower_try_table_begin(ctx, inst, block, handler_id)
TryTableEnd(handler_id) => lower_try_table_end(ctx, inst, block, handler_id)
GetExceptionTag => lower_get_exception_tag(ctx, inst, block)
GetExceptionValue(idx) => lower_get_exception_value(ctx, inst, block, idx)
GetExceptionValueCount => lower_get_exception_value_count(ctx, inst, block)
Delegate(depth) => lower_delegate(ctx, inst, block, depth)
SpillLocalsForThrow(count) =>
lower_spill_locals_for_throw(ctx, inst, block, count)
GetSpilledLocal(idx) => lower_get_spilled_local(ctx, inst, block, idx)
}
Handled(block)
}
///|
pub fn lower_function(
func : @milkir.Function,
context_slots : WasmContextSlots,
isa? : @isa.ISA = AArch64,
embedding_abi? : @abi.EmbeddingABI? = None,
runtime_symbols? : @wasm_milkir.RuntimeSymbols = @wasm_milkir.RuntimeSymbols::with_runtime_prefix(
"wasm.runtime",
),
num_imports? : Int = -1,
run_ir_opt? : Bool = true,
trap_payload_resolver? : (String) -> Int = fn(_reason) { 0 },
use_subtype_indirect_check? : Bool = true,
canonical_type_indices? : Array[Int] = [],
) -> @machv.Function {
let options : WasmLoweringOptions = {
use_subtype_indirect_check,
canonical_type_indices,
context_slots,
}
fn lower_extension(
ctx : @lower.LoweringContext,
inst : @milkir.Inst,
block : @block.Block,
ext : @milkir.ExtOp,
) -> @lower.ExtensionLowerResult {
lower_extension_with_options(options, ctx, inst, block, ext)
}
@lower.lower_dialect_function(
func,
lower_extension,
isa~,
embedding_abi~,
external_helper_symbols=external_helper_symbols(runtime_symbols),
trap_payload_resolver~,
num_imports~,
run_ir_opt~,
)
}