From e208430abfb69024525f4460f0b12ffd47d81444 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 22 Jun 2026 16:26:07 -0700 Subject: [PATCH] Make clearing and restoring the `may_leave` flag more amenable to optimization The clear-and-restore is now structured so that if translation doesn't actually call any functions (e.g. due to inlining) then a future dead-store elimination pass in Cranelift can remove all the flag juggling entirely (other than trapping when `!may_leave`): may_leave = load vmctx+MAY_LEAVE_OFFSET ;; (0) trapz may_leave ... zero = iconst 0 store zero, vmctx+MAY_LEAVE_OFFSET ;; (1) ... store may_leave, vmctx+MAY_LEAVE_OFFSET ;; (2) First, the dead-store elimination pass will see that the the store at (1): is dead and remove it. Then, the idempotent-store eliminator will recognize that the store at (2) is storing the same value that the memory location already contains and it will also be removed. The more we can reuse locals to make this idempotency obvious, rather than force Cranelift's optimizer to rediscover this information, the better. --- crates/cranelift/src/alias_region.rs | 6 +- crates/cranelift/src/compiler/component.rs | 13 +- .../src/component/vmcomponent_offsets.rs | 18 +-- crates/environ/src/fact/trampoline.rs | 129 ++++++++++++------ crates/wasmtime/src/runtime/vm/component.rs | 16 +-- ...-may-leave-without-signals-based-traps.wat | 34 ++--- .../direct-adapter-calls-inlining.wat | 45 +++--- .../direct-adapter-calls-x64.wat | 95 ++++++------- .../component-model/direct-adapter-calls.wat | 65 ++++----- .../disas/riscv64-component-builtins-asm.wat | 17 ++- tests/disas/riscv64-component-builtins.wat | 26 ++-- 11 files changed, 238 insertions(+), 226 deletions(-) diff --git a/crates/cranelift/src/alias_region.rs b/crates/cranelift/src/alias_region.rs index a7653858a72a..2aee704cf60c 100644 --- a/crates/cranelift/src/alias_region.rs +++ b/crates/cranelift/src/alias_region.rs @@ -1631,8 +1631,8 @@ impl AliasRegions> { ) } - /// Load a component instance's flags from the `VMComponentContext`. - pub fn vmcomponent_instance_flags( + /// Load a component instance's `may_leave` flag from the `VMComponentContext`. + pub fn vmcomponent_instance_may_leave( &mut self, cursor: &mut FuncCursor<'_>, vmctx: ir::Value, @@ -1643,7 +1643,7 @@ impl AliasRegions> { ir::types::I32, ir::MemFlagsData::trusted(), vmctx, - self.offsets.instance_flags(instance), + self.offsets.may_leave(instance), ) } } diff --git a/crates/cranelift/src/compiler/component.rs b/crates/cranelift/src/compiler/component.rs index a0a6836e7a0c..74d706294308 100644 --- a/crates/cranelift/src/compiler/component.rs +++ b/crates/cranelift/src/compiler/component.rs @@ -1113,9 +1113,8 @@ impl<'a> TrampolineCompiler<'a> { // run_destructor_block: // ;; test may_leave, but only if the component instances // ;; differ - // flags = load.i32 vmctx+$instance_flags_offset - // masked = band flags, $FLAG_MAY_LEAVE - // trapz masked, $TRAP_CANNOT_LEAVE_COMPONENT + // may_leave = load.i32 vmctx+$instance_flags_offset + // trapz may_leave, $TRAP_CANNOT_LEAVE_COMPONENT // // ;; set may_block to false, saving the old value to restore // ;; later, but only if the component instances differ and @@ -1527,17 +1526,13 @@ impl<'a> TrampolineCompiler<'a> { fn check_may_leave_instance(&mut self, instance: RuntimeComponentInstanceIndex) { let vmctx = self.builder.func.dfg.block_params(self.block0)[0]; - let flags = self.alias_regions.vmcomponent_instance_flags( + let may_leave = self.alias_regions.vmcomponent_instance_may_leave( &mut self.builder.cursor(), vmctx, instance, ); - let may_leave_bit = self - .builder - .ins() - .band_imm_u(flags, i64::from(FLAG_MAY_LEAVE)); let (mut traps, builder) = self.traps(); - traps.trapz(builder, may_leave_bit, TRAP_CANNOT_LEAVE_COMPONENT); + traps.trapz(builder, may_leave, TRAP_CANNOT_LEAVE_COMPONENT); } fn traps( diff --git a/crates/environ/src/component/vmcomponent_offsets.rs b/crates/environ/src/component/vmcomponent_offsets.rs index 4983314fc5d8..9c5f3b330803 100644 --- a/crates/environ/src/component/vmcomponent_offsets.rs +++ b/crates/environ/src/component/vmcomponent_offsets.rs @@ -4,7 +4,7 @@ // magic: u32, // builtins: &'static VMComponentBuiltins, // limits: *const VMStoreContext, -// flags: [VMGlobalDefinition; component.num_runtime_component_instances], +// may_leave: [VMGlobalDefinition; component.num_runtime_component_instances], // task_may_block: u32, // trampoline_func_refs: [VMFuncRef; component.num_trampolines], // unsafe_intrinsics: [VMFuncRef; component.num_unsafe_intrinsics], @@ -26,10 +26,6 @@ use crate::component::*; /// double-checked on `VMComponentContext::from_opaque`. pub const VMCOMPONENT_MAGIC: u32 = u32::from_le_bytes(*b"comp"); -/// Flag for the `VMComponentContext::flags` field which corresponds to the -/// canonical ABI flag `may_leave` -pub const FLAG_MAY_LEAVE: i32 = 1 << 0; - /// Runtime offsets within a `VMComponentContext` for a specific component. #[derive(Debug, Clone, Copy)] pub struct VMComponentOffsets

{ @@ -63,7 +59,7 @@ pub struct VMComponentOffsets

{ magic: u32, builtins: u32, vm_store_context: u32, - flags: u32, + may_leave: u32, task_may_block: u32, trampoline_func_refs: u32, intrinsic_func_refs: u32, @@ -132,7 +128,7 @@ impl VMComponentOffsets

{ magic: 0, builtins: 0, vm_store_context: 0, - flags: 0, + may_leave: 0, task_may_block: 0, trampoline_func_refs: 0, intrinsic_func_refs: 0, @@ -176,7 +172,7 @@ impl VMComponentOffsets

{ size(builtins) = ret.ptr.size(), size(vm_store_context) = ret.ptr.size(), align(16), - size(flags) = cmul(ret.num_runtime_component_instances, ret.ptr.size_of_vmglobal_definition()), + size(may_leave) = cmul(ret.num_runtime_component_instances, ret.ptr.size_of_vmglobal_definition()), size(task_may_block) = ret.ptr.size_of_vmglobal_definition(), align(u32::from(ret.ptr.size())), size(trampoline_func_refs) = cmul(ret.num_trampolines, ret.ptr.size_of_vm_func_ref()), @@ -218,11 +214,11 @@ impl VMComponentOffsets

{ self.builtins } - /// The offset of the `flags` field. + /// The offset of the `may_leave` flag for the given component instance. #[inline] - pub fn instance_flags(&self, index: RuntimeComponentInstanceIndex) -> u32 { + pub fn may_leave(&self, index: RuntimeComponentInstanceIndex) -> u32 { assert!(index.as_u32() < self.num_runtime_component_instances); - self.flags + index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition()) + self.may_leave + index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition()) } /// The offset of the `task_may_block` field. diff --git a/crates/environ/src/fact/trampoline.rs b/crates/environ/src/fact/trampoline.rs index d046a998b76c..4539ad13ecb8 100644 --- a/crates/environ/src/fact/trampoline.rs +++ b/crates/environ/src/fact/trampoline.rs @@ -16,13 +16,12 @@ //! can be somewhat arbitrary, an intentional decision. use crate::component::{ - CanonicalAbiInfo, ComponentTypesBuilder, FLAG_MAY_LEAVE, FixedEncoding as FE, FlatType, - InterfaceType, MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT, - PREPARE_ASYNC_WITH_RESULT, START_FLAG_ASYNC_CALLEE, StringEncoding, Transcode, - TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFixedLengthListIndex, - TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeOptionIndex, - TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex, - TypeVariantIndex, VariantInfo, + CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType, + MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, PREPARE_ASYNC_NO_RESULT, PREPARE_ASYNC_WITH_RESULT, + START_FLAG_ASYNC_CALLEE, StringEncoding, Transcode, TypeComponentLocalErrorContextTableIndex, + TypeEnumIndex, TypeFixedLengthListIndex, TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, + TypeMapIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, + TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo, }; use crate::fact::signature::Signature; use crate::fact::transcode::Transcoder; @@ -701,9 +700,9 @@ impl<'a, 'b> Compiler<'a, 'b> { .map(|(i, ty)| (i as u32, *ty)) .collect::>(); - self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false); + let saved = self.clear_may_leave(adapter.lift.flags); self.translate_params(adapter, ¶m_locals); - self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true); + self.restore_may_leave(adapter.lift.flags, saved); self.finish(); } @@ -727,7 +726,7 @@ impl<'a, 'b> Compiler<'a, 'b> { .map(|(i, ty)| (i as u32, *ty)) .collect::>(); - self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false); + let saved = self.clear_may_leave(adapter.lower.flags); // Note that we pass `param_locals` as _both_ the `param_locals` and // `result_locals` parameters to `translate_results`. That's because // the _parameters_ to `task.return` are actually the _results_ that the @@ -739,7 +738,7 @@ impl<'a, 'b> Compiler<'a, 'b> { // the import is lowered async, in which case `translate_results` will // use that pointer to store the results. self.translate_results(adapter, ¶m_locals, ¶m_locals); - self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true); + self.restore_may_leave(adapter.lower.flags, saved); self.finish() } @@ -763,11 +762,12 @@ impl<'a, 'b> Compiler<'a, 'b> { // This inserts the initial check required by `canon_lower` that the // caller instance can be left and additionally checks the // flags on the callee if necessary whether it can be entered. - self.trap_if_not_flag( - adapter.lower.flags, - FLAG_MAY_LEAVE, - Trap::CannotLeaveComponent, - ); + // + // The loaded `may_leave` value is saved into `saved_lower_may_leave` + // so that it can be restored after results are translated below + // without reloading the global. + let saved_lower_may_leave = + self.trap_if_not_may_leave(adapter.lower.flags, Trap::CannotLeaveComponent); let old_task_may_block = if self.module.tunables.concurrency_support { // Save, clear, and later restore the `may_block` field. @@ -823,8 +823,8 @@ impl<'a, 'b> Compiler<'a, 'b> { None }; - // Perform the translation of arguments. Note that `FLAG_MAY_LEAVE` is - // cleared around this invocation for the callee as per the + // Perform the translation of arguments. Note that the `may_leave` flag + // is cleared around this invocation for the callee as per the // `canon_lift` definition in the spec. Additionally note that the // precise ordering of traps here is not required since internal state // is not visible to either instance and a trap will "lock down" both @@ -832,10 +832,32 @@ impl<'a, 'b> Compiler<'a, 'b> { // reorder lifts/lowers and flags and such as is necessary and // convenient here. // - // TODO: if translation doesn't actually call any functions in either - // instance then there's no need to set/clear the flag here and that can - // be optimized away. - self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false); + // The clear-and-restore is structured (a constant `0` store to clear, + // then a store of the saved original value to restore) so that if + // translation doesn't actually call any functions in either instance + // then a future dead-store elimination pass in Cranelift can remove all + // the flag juggling entirely (other than trapping when `!may_leave`): + // + // may_leave = load vmctx+MAY_LEAVE_OFFSET ;; (0) + // trapz may_leave + // + // ... + // + // zero = iconst 0 + // store zero, vmctx+MAY_LEAVE_OFFSET ;; (1) + // + // ... + // + // store may_leave, vmctx+MAY_LEAVE_OFFSET ;; (2) + // + // First, the dead-store elimination pass will see that the the store at + // (1) is dead and remove it. Then, the idempotent-store eliminator will + // recognize that the store at (2) is storing the same value that the + // memory location already contains and it will also be removed. The + // more we can reuse locals to make this idempotency obvious, rather + // than force Cranelift's optimizer to rediscover this information, the + // better. + let saved_lift_may_leave = self.clear_may_leave(adapter.lift.flags); let param_locals = lower_sig .params .iter() @@ -843,7 +865,7 @@ impl<'a, 'b> Compiler<'a, 'b> { .map(|(i, ty)| (i as u32, *ty)) .collect::>(); self.translate_params(adapter, ¶m_locals); - self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true); + self.restore_may_leave(adapter.lift.flags, saved_lift_may_leave); // With all the arguments on the stack the actual target function is // now invoked. The core wasm results of the function are then placed @@ -882,12 +904,9 @@ impl<'a, 'b> Compiler<'a, 'b> { // order of everything doesn't matter since intermediate states cannot // be witnessed, hence the setting of flags here to encapsulate both // liftings and lowerings. - // - // TODO: like above the management of the `MAY_LEAVE` flag can probably - // be elided here for "simple" results. - self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false); + self.set_may_leave_false(adapter.lower.flags); self.translate_results(adapter, ¶m_locals, &result_locals); - self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true); + self.restore_may_leave(adapter.lower.flags, saved_lower_may_leave); // And finally post-return state is handled here once all results/etc // are all translated. @@ -3575,26 +3594,58 @@ impl<'a, 'b> Compiler<'a, 'b> { } } - fn trap_if_not_flag(&mut self, flags_global: GlobalIndex, flag_to_test: i32, trap: Trap) { + /// Loads the `may_leave` flag for the given instance, traps with `trap` if + /// it is not set, and returns a temporary local holding the loaded value + /// so that it can later be restored with `restore_may_leave` without + /// reloading the global. + /// + /// The `may_leave` flag is a boolean (0 or 1) so no masking is required. + fn trap_if_not_may_leave(&mut self, flags_global: GlobalIndex, trap: Trap) -> TempLocal { self.instruction(GlobalGet(flags_global.as_u32())); - self.instruction(I32Const(flag_to_test)); - self.instruction(I32And); + // Save the flag's value (known to be `true` whenever the trap below is + // not taken) into a temporary for later restoration. + let saved = self.local_tee_new_tmp(ValType::I32); self.instruction(I32Eqz); self.instruction(If(BlockType::Empty)); self.trap(trap); self.instruction(End); + saved } - fn set_flag(&mut self, flags_global: GlobalIndex, flag_to_set: i32, value: bool) { + /// Saves the current value of the `may_leave` flag into a fresh temporary + /// local (returned) and then clears the flag to `false`. + fn clear_may_leave(&mut self, flags_global: GlobalIndex) -> TempLocal { self.instruction(GlobalGet(flags_global.as_u32())); - if value { - self.instruction(I32Const(flag_to_set)); - self.instruction(I32Or); - } else { - self.instruction(I32Const(!flag_to_set)); - self.instruction(I32And); - } + let saved = self.local_set_new_tmp(ValType::I32); + self.set_may_leave_false(flags_global); + saved + } + + /// Sets the `may_leave` flag to `false` by storing a constant `0`. + /// + /// Since there is only a single flag there is no need to reload the global + /// and mask: storing `0` is sufficient. + fn set_may_leave_false(&mut self, flags_global: GlobalIndex) { + self.instruction(I32Const(0)); + self.instruction(GlobalSet(flags_global.as_u32())); + } + + /// Restores the `may_leave` flag to the value previously saved in `saved` + /// (via `clear_may_leave` or `trap_if_not_may_leave`) and frees the + /// temporary local. + /// + /// Storing the previously-loaded value (rather than reloading the global + /// and or-ing in the flag bit) makes it clear in the generated CLIF that + /// the same value that was there before is being written back. Combined + /// with the constant `0` store in `set_may_leave_false`, this lets a future + /// dead-store-elimination pass remove the clear-to-`false` store which will + /// then allow our idempotent-store elimination to remove this restore for + /// adapters whose body never touches the flag (e.g. simple inlined + /// callees). + fn restore_may_leave(&mut self, flags_global: GlobalIndex, saved: TempLocal) { + self.instruction(LocalGet(saved.idx)); self.instruction(GlobalSet(flags_global.as_u32())); + self.free_temp_local(saved); } fn assert_aligned(&mut self, ty: &InterfaceType, mem: &Memory) { diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index e088657a6cec..de21c6738bfd 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -365,8 +365,8 @@ impl ComponentInstance { #[inline] pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags { unsafe { - let ptr = self - .vmctx_plus_offset_raw::(self.offsets.instance_flags(instance)); + let ptr = + self.vmctx_plus_offset_raw::(self.offsets.may_leave(instance)); InstanceFlags(SendSyncPtr::new(ptr)) } } @@ -704,9 +704,9 @@ impl ComponentInstance { let i = RuntimeComponentInstanceIndex::from_u32(i); let mut def = VMGlobalDefinition::new(); // SAFETY: this is a valid initialization of all globals which are - // 32-bit values. + // 32-bit values. The `may_leave` flag starts out `true`. unsafe { - *def.as_i32_mut() = FLAG_MAY_LEAVE; + *def.as_i32_mut() = 1; self.instance_flags(i).as_raw().write(def); } } @@ -1062,17 +1062,13 @@ impl InstanceFlags { #[inline] pub unsafe fn may_leave(&self) -> bool { - unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0 } + unsafe { *self.as_raw().as_ref().as_i32() != 0 } } #[inline] pub unsafe fn set_may_leave(&mut self, val: bool) { unsafe { - if val { - *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE; - } else { - *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE; - } + *self.as_raw().as_mut().as_i32_mut() = val as i32; } } diff --git a/tests/disas/component-may-leave-without-signals-based-traps.wat b/tests/disas/component-may-leave-without-signals-based-traps.wat index ef878974ae3f..d9834361eaea 100644 --- a/tests/disas/component-may-leave-without-signals-based-traps.wat +++ b/tests/disas/component-may-leave-without-signals-based-traps.wat @@ -25,9 +25,9 @@ ;; movq 8(%rcx), %rcx ;; movq %rcx, 0x38(%rax) ;; movl 0x20(%rdi), %eax -;; testl $1, %eax -;; je 0x13e -;; fe: movq 8(%rdi), %rax +;; testl %eax, %eax +;; je 0x13b +;; fb: movq 8(%rdi), %rax ;; movq (%rax), %rax ;; xorl %ecx, %ecx ;; movl %ecx, %esi @@ -36,21 +36,21 @@ ;; movl %ecx, %ecx ;; callq *%rax ;; cmpq $-1, %rax -;; je 0x129 -;; 11c: movq (%rsp), %rbx +;; je 0x126 +;; 119: movq (%rsp), %rbx ;; addq $0x10, %rsp ;; movq %rbp, %rsp ;; popq %rbp ;; retq -;; 129: movq %rbx, %rsi -;; 12c: movq 0x10(%rsi), %rax -;; 130: movq 0x148(%rax), %rax -;; 137: movq %rbx, %rdi -;; 13a: callq *%rax -;; 13c: ud2 -;; 13e: movl $0x17, %esi -;; 143: movq %rbx, %rdi -;; 146: callq 0x6a -;; 14b: movq %rbx, %rdi -;; 14e: callq 0x9b -;; 153: ud2 +;; 126: movq %rbx, %rsi +;; 129: movq 0x10(%rsi), %rax +;; 12d: movq 0x148(%rax), %rax +;; 134: movq %rbx, %rdi +;; 137: callq *%rax +;; 139: ud2 +;; 13b: movl $0x17, %esi +;; 140: movq %rbx, %rdi +;; 143: callq 0x6a +;; 148: movq %rbx, %rdi +;; 14b: callq 0x9b +;; 150: ud2 diff --git a/tests/disas/component-model/direct-adapter-calls-inlining.wat b/tests/disas/component-model/direct-adapter-calls-inlining.wat index d990e66dc0dc..d5663715aa89 100644 --- a/tests/disas/component-model/direct-adapter-calls-inlining.wat +++ b/tests/disas/component-model/direct-adapter-calls-inlining.wat @@ -92,30 +92,25 @@ ;; @00ee v4 = load.i64 notrap aligned readonly can_move region2 v0+72 ;; v14 = load.i64 notrap aligned readonly can_move region3 v4+136 ;; v15 = load.i32 notrap aligned region4 v14 -;; v16 = iconst.i32 1 -;; v17 = band v15, v16 ; v16 = 1 ;; v13 = iconst.i32 0 -;; v19 = icmp eq v17, v13 ; v13 = 0 -;; brif v19, block9, block10 +;; v17 = icmp eq v15, v13 ; v13 = 0 +;; brif v17, block9, block10 ;; ;; block9: -;; v23 = load.i64 notrap aligned readonly can_move region6 v4+88 -;; v22 = load.i64 notrap aligned readonly can_move region5 v4+104 -;; v21 = iconst.i32 23 -;; try_call_indirect v23(v22, v4, v21), sig1, block11, [ context v4, default: block8(exn0) ] ; v21 = 23 +;; v21 = load.i64 notrap aligned readonly can_move region6 v4+88 +;; v20 = load.i64 notrap aligned readonly can_move region5 v4+104 +;; v19 = iconst.i32 23 +;; try_call_indirect v21(v20, v4, v19), sig1, block11, [ context v4, default: block8(exn0) ] ; v19 = 23 ;; ;; block11: ;; trap user12 ;; ;; block10: -;; v28 = load.i64 notrap aligned readonly can_move region7 v4+112 -;; v29 = load.i32 notrap aligned region4 v28 -;; v30 = iconst.i32 -2 -;; v31 = band v29, v30 ; v30 = -2 -;; store notrap aligned region4 v31, v28 -;; v61 = iconst.i32 1 -;; v62 = bor v29, v61 ; v61 = 1 -;; store notrap aligned region4 v62, v28 +;; v26 = load.i64 notrap aligned readonly can_move region7 v4+112 +;; v27 = load.i32 notrap aligned region4 v26 +;; v43 = iconst.i32 0 +;; store notrap aligned region4 v43, v26 ; v43 = 0 +;; store notrap aligned region4 v27, v26 ;; jump block13 ;; ;; block13: @@ -125,21 +120,17 @@ ;; jump block12 ;; ;; block12: -;; v42 = load.i32 notrap aligned region4 v14 -;; v63 = iconst.i32 -2 -;; v64 = band v42, v63 ; v63 = -2 -;; store notrap aligned region4 v64, v14 -;; v65 = iconst.i32 1 -;; v66 = bor v42, v65 ; v65 = 1 -;; store notrap aligned region4 v66, v14 +;; v44 = iconst.i32 0 +;; store notrap aligned region4 v44, v14 ; v44 = 0 +;; store.i32 notrap aligned region4 v15, v14 ;; jump block7 ;; ;; block7: ;; jump block4 ;; ;; block5: -;; v25 = iconst.i32 49 -;; call_indirect.i64 sig1, v23(v22, v4, v25) ; v25 = 49 +;; v23 = iconst.i32 49 +;; call_indirect.i64 sig1, v21(v20, v4, v23) ; v23 = 49 ;; trap user12 ;; ;; block4: @@ -152,6 +143,6 @@ ;; @00f0 jump block1 ;; ;; block1: -;; v53 = iconst.i32 1276 -;; @00f0 return v53 ; v53 = 1276 +;; v37 = iconst.i32 1276 +;; @00f0 return v37 ; v37 = 1276 ;; } diff --git a/tests/disas/component-model/direct-adapter-calls-x64.wat b/tests/disas/component-model/direct-adapter-calls-x64.wat index 3dcbe79db152..8dd507783d58 100644 --- a/tests/disas/component-model/direct-adapter-calls-x64.wat +++ b/tests/disas/component-model/direct-adapter-calls-x64.wat @@ -85,65 +85,60 @@ ;; movq %rsp, %rbp ;; movq 8(%rdi), %r10 ;; movq 0x18(%r10), %r10 -;; addq $0x50, %r10 +;; addq $0x60, %r10 ;; cmpq %rsp, %r10 -;; ja 0x147 -;; 79: subq $0x40, %rsp -;; movq %rbx, 0x10(%rsp) -;; movq %r12, 0x18(%rsp) -;; movq %r13, 0x20(%rsp) -;; movq %r14, 0x28(%rsp) -;; movq %r15, 0x30(%rsp) +;; ja 0x13e +;; 79: subq $0x50, %rsp +;; movq %rbx, 0x20(%rsp) +;; movq %r12, 0x28(%rsp) +;; movq %r13, 0x30(%rsp) +;; movq %r14, 0x38(%rsp) +;; movq %r15, 0x40(%rsp) ;; movq %rdi, (%rsp) ;; movq (%rsp), %rdi -;; movq 0x88(%rdi), %r8 -;; movl (%r8), %eax -;; movq %r8, 8(%rsp) -;; testl $1, %eax -;; je 0x115 -;; b8: movq (%rsp), %rdi +;; movq 0x88(%rdi), %rcx +;; movl (%rcx), %esi +;; movq %rcx, 0x10(%rsp) +;; testl %esi, %esi +;; movq %rsi, 8(%rsp) +;; je 0x10c +;; b9: movq (%rsp), %rdi ;; movq 0x70(%rdi), %rax ;; movl (%rax), %ecx -;; movq %rcx, %rsi -;; andl $0xfffffffe, %esi -;; movl %esi, (%rax) -;; orl $1, %ecx +;; movl $0, (%rax) ;; movl %ecx, (%rax) ;; movq 0x48(%rdi), %rdi ;; movq (%rsp), %rsi ;; callq 0 -;; ├─╼ exception frame offset: SP = FP - 0x40 -;; ╰─╼ exception handler: default handler, context at [SP+0x0], handler=0x12e -;; movq 8(%rsp), %r8 -;; movl (%r8), %ecx -;; movq %rcx, %rsi -;; andl $0xfffffffe, %esi -;; movl %esi, (%r8) -;; orl $1, %ecx -;; movl %ecx, (%r8) -;; movq 0x10(%rsp), %rbx -;; movq 0x18(%rsp), %r12 -;; movq 0x20(%rsp), %r13 -;; movq 0x28(%rsp), %r14 -;; movq 0x30(%rsp), %r15 -;; addq $0x40, %rsp +;; ├─╼ exception frame offset: SP = FP - 0x50 +;; ╰─╼ exception handler: default handler, context at [SP+0x0], handler=0x125 +;; movq 0x10(%rsp), %rcx +;; movl $0, (%rcx) +;; movq 8(%rsp), %rsi +;; movl %esi, (%rcx) +;; movq 0x20(%rsp), %rbx +;; movq 0x28(%rsp), %r12 +;; movq 0x30(%rsp), %r13 +;; movq 0x38(%rsp), %r14 +;; movq 0x40(%rsp), %r15 +;; addq $0x50, %rsp ;; movq %rbp, %rsp ;; popq %rbp ;; retq -;; 115: movq (%rsp), %rcx -;; 119: movq 0x58(%rcx), %rax -;; 11d: movq 0x68(%rcx), %rdi -;; 121: movl $0x17, %edx -;; 126: movq (%rsp), %rsi -;; 12a: callq *%rax -;; ├─╼ exception frame offset: SP = FP - 0x40 -;; ╰─╼ exception handler: default handler, context at [SP+0x0], handler=0x12e -;; 12c: ud2 -;; 12e: movq (%rsp), %rcx -;; 132: movq 0x58(%rcx), %rax -;; 136: movq 0x68(%rcx), %rdi -;; 13a: movl $0x31, %edx -;; 13f: movq (%rsp), %rsi -;; 143: callq *%rax -;; 145: ud2 -;; 147: ud2 +;; 10c: movq (%rsp), %rcx +;; 110: movq 0x58(%rcx), %rax +;; 114: movq 0x68(%rcx), %rdi +;; 118: movl $0x17, %edx +;; 11d: movq (%rsp), %rsi +;; 121: callq *%rax +;; ├─╼ exception frame offset: SP = FP - 0x50 +;; ╰─╼ exception handler: default handler, context at [SP+0x0], handler=0x125 +;; 123: ud2 +;; 125: movq (%rsp), %rcx +;; 129: movq 0x58(%rcx), %rax +;; 12d: movq 0x68(%rcx), %rdi +;; 131: movl $0x31, %edx +;; 136: movq (%rsp), %rsi +;; 13a: callq *%rax +;; 13c: ud2 +;; 13e: ud2 diff --git a/tests/disas/component-model/direct-adapter-calls.wat b/tests/disas/component-model/direct-adapter-calls.wat index 5e24a00ea01d..2dc06561d0f1 100644 --- a/tests/disas/component-model/direct-adapter-calls.wat +++ b/tests/disas/component-model/direct-adapter-calls.wat @@ -121,56 +121,47 @@ ;; block4: ;; @0080 v9 = load.i64 notrap aligned readonly can_move region2 v0+136 ;; @0080 v10 = load.i32 notrap aligned region3 v9 -;; @0082 v11 = iconst.i32 1 -;; @0084 v12 = band v10, v11 ; v11 = 1 ;; @0075 v4 = iconst.i32 0 -;; @0085 v14 = icmp eq v12, v4 ; v4 = 0 -;; @0086 brif v14, block7, block8 +;; @0084 v12 = icmp eq v10, v4 ; v4 = 0 +;; @0085 brif v12, block7, block8 ;; ;; block7: -;; @008a v18 = load.i64 notrap aligned readonly can_move region5 v0+88 -;; @008a v17 = load.i64 notrap aligned readonly can_move region4 v0+104 -;; @0088 v16 = iconst.i32 23 -;; @008a try_call_indirect v18(v17, v0, v16), sig0, block9, [ context v0, default: block6(exn0) ] ; v16 = 23 +;; @0089 v16 = load.i64 notrap aligned readonly can_move region5 v0+88 +;; @0089 v15 = load.i64 notrap aligned readonly can_move region4 v0+104 +;; @0087 v14 = iconst.i32 23 +;; @0089 try_call_indirect v16(v15, v0, v14), sig0, block9, [ context v0, default: block6(exn0) ] ; v14 = 23 ;; ;; block9: -;; @008c trap user12 +;; @008b trap user12 ;; ;; block8: -;; @008e v19 = load.i64 notrap aligned readonly can_move region6 v0+112 -;; @008e v20 = load.i32 notrap aligned region3 v19 -;; @0090 v21 = iconst.i32 -2 -;; @0092 v22 = band v20, v21 ; v21 = -2 -;; @0093 store notrap aligned region3 v22, v19 -;; v48 = iconst.i32 1 -;; v49 = bor v20, v48 ; v48 = 1 -;; @009c store notrap aligned region3 v49, v19 -;; @009e v29 = load.i64 notrap aligned readonly can_move region7 v0+72 -;; @009e try_call fn0(v29, v0, v2), sig1, block10(ret0), [ context v0, default: block6(exn0) ] -;; -;; block10(v30: i32): -;; @00a2 v32 = load.i32 notrap aligned region3 v9 -;; v50 = iconst.i32 -2 -;; v51 = band v32, v50 ; v50 = -2 -;; @00a7 store notrap aligned region3 v51, v9 -;; v52 = iconst.i32 1 -;; v53 = bor v32, v52 ; v52 = 1 -;; @00b0 store notrap aligned region3 v53, v9 -;; @00b2 jump block5(v30) +;; @008d v17 = load.i64 notrap aligned readonly can_move region6 v0+112 +;; @008d v18 = load.i32 notrap aligned region3 v17 +;; v30 = iconst.i32 0 +;; @0093 store notrap aligned region3 v30, v17 ; v30 = 0 +;; @0099 store notrap aligned region3 v18, v17 +;; @009b v22 = load.i64 notrap aligned readonly can_move region7 v0+72 +;; @009b try_call fn0(v22, v0, v2), sig1, block10(ret0), [ context v0, default: block6(exn0) ] +;; +;; block10(v23: i32): +;; v31 = iconst.i32 0 +;; @00a1 store notrap aligned region3 v31, v9 ; v31 = 0 +;; @00a7 store.i32 notrap aligned region3 v10, v9 +;; @00a9 jump block5(v23) ;; ;; block5(v6: i32): -;; @00b3 jump block2(v6) +;; @00aa jump block2(v6) ;; ;; block3: -;; v54 = load.i64 notrap aligned readonly can_move region5 v0+88 -;; v55 = load.i64 notrap aligned readonly can_move region4 v0+104 -;; @00b6 v41 = iconst.i32 49 -;; @00b8 call_indirect sig0, v54(v55, v0, v41) ; v41 = 49 -;; @00ba trap user12 +;; v32 = load.i64 notrap aligned readonly can_move region5 v0+88 +;; v33 = load.i64 notrap aligned readonly can_move region4 v0+104 +;; @00ad v27 = iconst.i32 49 +;; @00af call_indirect sig0, v32(v33, v0, v27) ; v27 = 49 +;; @00b1 trap user12 ;; ;; block2(v5: i32): -;; @00bc jump block1(v5) +;; @00b3 jump block1(v5) ;; ;; block1(v3: i32): -;; @00bc return v3 +;; @00b3 return v3 ;; } diff --git a/tests/disas/riscv64-component-builtins-asm.wat b/tests/disas/riscv64-component-builtins-asm.wat index 434980861b36..9a71f7ea3047 100644 --- a/tests/disas/riscv64-component-builtins-asm.wat +++ b/tests/disas/riscv64-component-builtins-asm.wat @@ -17,17 +17,16 @@ ;; sd s0, 0(sp) ;; mv s0, sp ;; addi sp, sp, -0x10 -;; sd s5, 8(sp) -;; sd s9, 0(sp) -;; mv s5, a1 -;; mv s9, a2 +;; sd s4, 8(sp) +;; sd s8, 0(sp) +;; mv s4, a1 +;; mv s8, a2 ;; mv a3, s0 ;; ld a1, 8(a1) ;; sd a3, 0x30(a1) ;; ld a2, 8(s0) ;; sd a2, 0x38(a1) ;; lw a1, 0x20(a0) -;; andi a1, a1, 1 ;; sext.w a1, a1 ;; bnez a1, 8 ;; .byte 0x00, 0x00, 0x00, 0x00 @@ -39,20 +38,20 @@ ;; srai a1, a1, 0x20 ;; slli a2, a4, 0x20 ;; srai a2, a2, 0x20 -;; mv a3, s9 +;; mv a3, s8 ;; slli a3, a3, 0x20 ;; srai a3, a3, 0x20 ;; jalr a5 ;; addi a1, zero, -1 ;; beq a0, a1, 0x20 -;; ld s5, 8(sp) -;; ld s9, 0(sp) +;; ld s4, 8(sp) +;; ld s8, 0(sp) ;; addi sp, sp, 0x10 ;; ld ra, 8(sp) ;; ld s0, 0(sp) ;; addi sp, sp, 0x10 ;; ret -;; mv a1, s5 +;; mv a1, s4 ;; ld a0, 0x10(a1) ;; ld a2, 0x148(a0) ;; mv a0, a1 diff --git a/tests/disas/riscv64-component-builtins.wat b/tests/disas/riscv64-component-builtins.wat index bee89c881388..46b0e1fff256 100644 --- a/tests/disas/riscv64-component-builtins.wat +++ b/tests/disas/riscv64-component-builtins.wat @@ -27,25 +27,23 @@ ;; v5 = get_return_address.i64 ;; store notrap aligned region2 v5, v3+56 ;; v6 = load.i32 notrap aligned region3 v0+32 -;; v7 = iconst.i32 1 -;; v8 = band v6, v7 ; v7 = 1 -;; trapz v8, user26 -;; v11 = load.i64 notrap aligned readonly region4 v0+8 -;; v12 = load.i64 notrap aligned readonly v11+16 -;; v9 = iconst.i32 0 -;; v13 = call_indirect sig0, v12(v0, v9, v9, v2) ; v9 = 0, v9 = 0 -;; v14 = iconst.i64 -1 -;; v15 = icmp ne v13, v14 ; v14 = -1 -;; brif v15, block2, block1 +;; trapz v6, user26 +;; v9 = load.i64 notrap aligned readonly region4 v0+8 +;; v10 = load.i64 notrap aligned readonly v9+16 +;; v7 = iconst.i32 0 +;; v11 = call_indirect sig0, v10(v0, v7, v7, v2) ; v7 = 0, v7 = 0 +;; v12 = iconst.i64 -1 +;; v13 = icmp ne v11, v12 ; v12 = -1 +;; brif v13, block2, block1 ;; ;; block1 cold: -;; v16 = load.i64 notrap aligned readonly can_move region5 v1+16 -;; v17 = load.i64 notrap aligned readonly can_move v16+328 -;; call_indirect sig1, v17(v1) +;; v14 = load.i64 notrap aligned readonly can_move region5 v1+16 +;; v15 = load.i64 notrap aligned readonly can_move v14+328 +;; call_indirect sig1, v15(v1) ;; trap user1 ;; ;; block2: -;; brif.i64 v13, block3, block4 +;; brif.i64 v11, block3, block4 ;; ;; block3: ;; jump block4