Repository: bytecodealliance/wasmtime
Pull request #8099 (2024-03-12 15:49:12)

x64: Implement fallback for fcvt_from_sint.f64x2
This instruction was previously unimplemented in Cranelift as pointed out in #8084. While a fallback for `fcvt_from_uint` was implemented in #7919 I forgot to do the same for the signed version. This commit adds a fallback that decomposes the input into two scalars and converts each individually, then reassembling the result.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index ff529f58a..1af5217a0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4201,29 +4201,36 @@ dependencies = [
 
 [[package]]
 name = "wit-bindgen"
-version = "0.20.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e6058f3ef320faece2d48ab105a278e94bac47df03b04af69c205173e0afcc"
+checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27"
 dependencies = [
  "bitflags 2.4.1",
+ "wit-bindgen-rt",
  "wit-bindgen-rust-macro",
 ]
 
 [[package]]
 name = "wit-bindgen-core"
-version = "0.20.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a8abb3fed5dee9be41aef6609fe2bc4a9d10f82af24fe9b843e885d51ef638"
+checksum = "e85e72719ffbccf279359ad071497e47eb0675fe22106dea4ed2d8a7fcb60ba4"
 dependencies = [
  "anyhow",
  "wit-parser",
 ]
 
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb8738270f32a2d6739973cbbb7c1b6dd8959ce515578a6e19165853272ee64"
+
 [[package]]
 name = "wit-bindgen-rust"
-version = "0.20.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c63da73f9dc6b68c6aea864b3e277ddb056ec49bd3e41b2b76bc2165d769a9"
+checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3"
 dependencies = [
  "anyhow",
  "heck",
@@ -4235,9 +4242,9 @@ dependencies = [
 
 [[package]]
 name = "wit-bindgen-rust-macro"
-version = "0.20.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2adddfe43ab23342715b15225a32b29010f8af91ad9cab7a51a46c5006aea08e"
+checksum = "d376d3ae5850526dfd00d937faea0d81a06fa18f7ac1e26f386d760f241a8f4b"
 dependencies = [
  "anyhow",
  "proc-macro2",
diff --git a/Cargo.toml b/Cargo.toml
index d6972080e..c7431f823 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -228,7 +228,7 @@ io-lifetimes = { version = "2.0.3", default-features = false }
 io-extras = "0.18.1"
 rustix = "0.38.31"
 # wit-bindgen:
-wit-bindgen = { version = "0.20.0", default-features = false }
+wit-bindgen = { version = "0.22.0", default-features = false }
 
 # wasm-tools family:
 wasmparser = "0.201.0"
diff --git a/RELEASES.md b/RELEASES.md
index 93af3bd3f..30e58bfdc 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -16,8 +16,98 @@ Unreleased.
 
 ### Added
 
+* C API bindings for the sampling-based profiler in Wasmtime have been added.
+  [#7854](https://github.com/bytecodealliance/wasmtime/pull/7854)
+
+* Add the WasiP1Ctx to ease the use of `wasmtime-wasi` in place of `wasi-common`
+  [#8053](https://github.com/bytecodealliance/wasmtime/pull/8053)
+
+* The Winch compiler backend is now feature-complete for x64. Note that minor
+  issues and fuzz bugs are still being addressed, but now's a good time to test
+  if you're interested.
+  [#7894](https://github.com/bytecodealliance/wasmtime/pull/7894)
+  [#7909](https://github.com/bytecodealliance/wasmtime/pull/7909)
+  [#7927](https://github.com/bytecodealliance/wasmtime/pull/7927)
+  [#7932](https://github.com/bytecodealliance/wasmtime/pull/7932)
+  [#7949](https://github.com/bytecodealliance/wasmtime/pull/7949)
+  [#7974](https://github.com/bytecodealliance/wasmtime/pull/7974)
+  [#8001](https://github.com/bytecodealliance/wasmtime/pull/8001)
+
+* The typed function references proposal to WebAssembly is now fully
+  implemented.
+  [#7943](https://github.com/bytecodealliance/wasmtime/pull/7943)
+
+* The `component::Linker` type is now "semver aware" in that it enables loading
+  components referring to past or future versions of interfaces so long as the
+  types are compatible.
+  [#7994](https://github.com/bytecodealliance/wasmtime/pull/7994)
+
+* Wasmtime can now be built for "custom platforms" which is intended for
+  bare-metal builds.
+  [#7995](https://github.com/bytecodealliance/wasmtime/pull/7995)
+
+* The `wasmtime-wasi-nn` crate now has a backend based on WinML.
+  [#7807](https://github.com/bytecodealliance/wasmtime/pull/7807)
+
+* The `wasmtime` CLI now has flags for configuring limits of the pooling
+  allocator.
+  [#8027](https://github.com/bytecodealliance/wasmtime/pull/8027)
+
+
 ### Changed
 
+* The `wasmtime serve` command no longer binds its port with `SO_REUSEADDR`
+  meaning that if it is invoked twice only one will succeed.
+  [#7863](https://github.com/bytecodealliance/wasmtime/pull/7863)
+
+* The sampling-based profiler in Wasmtime now takes an explicit argument of
+  the time delta between samples.
+  [#7873](https://github.com/bytecodealliance/wasmtime/pull/7873)
+
+* Many accessors for type information now require an `&Engine` argument to be
+  specified in preparation for an implementation of wasm GC.
+  [#7892](https://github.com/bytecodealliance/wasmtime/pull/7892)
+
+* The `host` header is now forbidden in wasi-http.
+  [#7905](https://github.com/bytecodealliance/wasmtime/pull/7905)
+
+* Stronger type-checks are now performed for host-owned resources when
+  interacting with the component model to help catch mistakes earlier.
+  [#7902](https://github.com/bytecodealliance/wasmtime/pull/7902)
+
+* Demangling Rust and C/C++ symbols in WebAssembly modules is now done by
+  default in the C API.
+  [#7962](https://github.com/bytecodealliance/wasmtime/pull/7962)
+
+* Preview2-based APIs are now located at the root of the `wasmtime_wasi` crate
+  instead of a submodule.
+  [#7933](https://github.com/bytecodealliance/wasmtime/pull/7933)
+
+* Components now reserve index 0 for handle tables to match the component model
+  specification.
+  [#7661](https://github.com/bytecodealliance/wasmtime/pull/7661)
+
+* Support for `externref` has been moved behind a new `gc` Cargo feature. This
+  will also gate support for wasm gc in the future.
+  [#7975](https://github.com/bytecodealliance/wasmtime/pull/7975)
+
+* Require the `WASMTIME_WASI_CONFIG_PREOPEN_SOCKET_ALLOW` environment variable
+  to bet set to allow the use of `wasi_config_preopen_socket` via the c api, as
+  it will be deprecated in `20.0.0`.
+  [#8053](https://github.com/bytecodealliance/wasmtime/pull/8053)
+
+### Fixed
+
+* WIT interface names that are Rust keywords now correctly generate bindings.
+  [#7790](https://github.com/bytecodealliance/wasmtime/pull/7790)
+
+* PKRU state is now restored across await points.
+  [#7789](https://github.com/bytecodealliance/wasmtime/pull/7789)
+
+* Wasmtime now correctly supports `global.get` in all constant expressions
+  within a module.
+  [#7996](https://github.com/bytecodealliance/wasmtime/pull/7996)
+
 --------------------------------------------------------------------------------
 
 ## 18.0.2
diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle
index f07251c8b..c79a5d70a 100644
--- a/cranelift/codegen/src/isa/x64/inst.isle
+++ b/cranelift/codegen/src/isa/x64/inst.isle
@@ -966,6 +966,7 @@
             Ucomiss
             Ucomisd
             Unpcklps
+            Unpcklpd
             Unpckhps
             Xorps
             Xorpd
@@ -1279,6 +1280,7 @@
             Vpunpckhwd
             Vpunpcklwd
             Vunpcklps
+            Vunpcklpd
             Vunpckhps
             Vandnps
             Vandnpd
@@ -3296,6 +3298,14 @@
       (if-let $true (use_avx))
       (xmm_rmir_vex (AvxOpcode.Vunpcklps) src1 src2))
 
+;; Helper for creating `unpcklpd` instructions.
+(decl x64_unpcklpd (Xmm XmmMem) Xmm)
+(rule 0 (x64_unpcklpd src1 src2)
+      (xmm_rm_r (SseOpcode.Unpcklpd) src1 src2))
+(rule 1 (x64_unpcklpd src1 src2)
+      (if-let $true (use_avx))
+      (xmm_rmir_vex (AvxOpcode.Vunpcklpd) src1 src2))
+
 ;; Helper for creating `unpckhps` instructions.
 (decl x64_unpckhps (Xmm XmmMem) Xmm)
 (rule 0 (x64_unpckhps src1 src2)
diff --git a/cranelift/codegen/src/isa/x64/inst/args.rs b/cranelift/codegen/src/isa/x64/inst/args.rs
index 8d8182691..85c70b6b3 100644
--- a/cranelift/codegen/src/isa/x64/inst/args.rs
+++ b/cranelift/codegen/src/isa/x64/inst/args.rs
@@ -1151,6 +1151,7 @@ pub enum SseOpcode {
     Ucomiss,
     Ucomisd,
     Unpcklps,
+    Unpcklpd,
     Unpckhps,
     Xorps,
     Xorpd,
@@ -1309,7 +1310,8 @@ impl SseOpcode {
             | SseOpcode::Punpcklqdq
             | SseOpcode::Punpckhqdq
             | SseOpcode::Pshuflw
-            | SseOpcode::Pshufhw => SSE2,
+            | SseOpcode::Pshufhw
+            | SseOpcode::Unpcklpd => SSE2,
 
             SseOpcode::Pabsb
             | SseOpcode::Pabsw
@@ -1566,6 +1568,7 @@ impl fmt::Debug for SseOpcode {
             SseOpcode::Pshufhw => "pshufhw",
             SseOpcode::Pblendw => "pblendw",
             SseOpcode::Movddup => "movddup",
+            SseOpcode::Unpcklpd => "unpcklpd",
         };
         write!(fmt, "{}", name)
     }
@@ -1767,7 +1770,8 @@ impl AvxOpcode {
             | AvxOpcode::Vsqrtss
             | AvxOpcode::Vsqrtsd
             | AvxOpcode::Vroundss
-            | AvxOpcode::Vroundsd => {
+            | AvxOpcode::Vroundsd
+            | AvxOpcode::Vunpcklpd => {
                 smallvec![InstructionSet::AVX]
             }
 
diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs
index 9b17aad4e..3f947dae2 100644
--- a/cranelift/codegen/src/isa/x64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/x64/inst/emit.rs
@@ -2226,6 +2226,7 @@ pub(crate) fn emit(
                 SseOpcode::Cvtsd2ss => (LegacyPrefixes::_F2, 0x0F5A, 2),
                 SseOpcode::Sqrtss => (LegacyPrefixes::_F3, 0x0F51, 2),
                 SseOpcode::Sqrtsd => (LegacyPrefixes::_F2, 0x0F51, 2),
+                SseOpcode::Unpcklpd => (LegacyPrefixes::_66, 0x0F14, 2),
                 _ => unimplemented!("Opcode {:?} not implemented", op),
             };
 
@@ -2451,6 +2452,7 @@ pub(crate) fn emit(
                 AvxOpcode::Vcvtsd2ss => (LP::_F2, OM::_0F, 0x5A),
                 AvxOpcode::Vsqrtss => (LP::_F3, OM::_0F, 0x51),
                 AvxOpcode::Vsqrtsd => (LP::_F2, OM::_0F, 0x51),
+                AvxOpcode::Vunpcklpd => (LP::_66, OM::_0F, 0x14),
                 _ => panic!("unexpected rmir vex opcode {op:?}"),
             };
             VexInstruction::new()
diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle
index d872b8152..9bb01775e 100644
--- a/cranelift/codegen/src/isa/x64/lower.isle
+++ b/cranelift/codegen/src/isa/x64/lower.isle
@@ -3403,6 +3403,18 @@
 (rule 0 (lower (fcvt_from_sint a @ (value_type $I32X4)))
       (x64_cvtdq2ps a))
 
+;; Base case: decompose the i64x2 input into two scalar registers and convert
+;; each of those into a float. Afterwards re-pack the two results into the final
+;; destination.
+(rule 0 (lower (fcvt_from_sint a @ (value_type $I64X2)))
+      (let (
+          (a Xmm a)
+          (zero Xmm (xmm_zero $F64X2))
+          (f0 Xmm (x64_cvtsi2sd $I64 zero (x64_movq_to_gpr a)))
+          (f1 Xmm (x64_cvtsi2sd $I64 zero (x64_movq_to_gpr (x64_pshufd a 0b11_10_11_10))))
+        )
+        (x64_unpcklpd f0 f1)))
+
 (rule 1 (lower (has_type $F64X2 (fcvt_from_sint (swiden_low a @ (value_type $I32X4)))))
       (x64_cvtdq2pd a))
 
diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs
index 7a78d6f64..c7c8aec44 100644
--- a/crates/wasi-http/src/lib.rs
+++ b/crates/wasi-http/src/lib.rs
@@ -18,10 +18,11 @@ pub mod bindings {
         tracing: true,
         async: false,
         with: {
-            "wasi:io/error": wasmtime_wasi::bindings::io::error,
-            "wasi:io/streams": wasmtime_wasi::bindings::io::streams,
-            "wasi:io/poll": wasmtime_wasi::bindings::io::poll,
+            // Upstream package dependencies
+            "wasi:io": wasmtime_wasi::bindings::io,
 
+            // Configure all WIT http resources to be defined types in this
+            // crate to use the `ResourceTable` helper methods.
             "wasi:http/types/outgoing-body": super::body::HostOutgoingBody,
             "wasi:http/types/future-incoming-response": super::types::HostFutureIncomingResponse,
             "wasi:http/types/outgoing-response": super::types::HostOutgoingResponse,
diff --git a/crates/wasi-http/src/proxy.rs b/crates/wasi-http/src/proxy.rs
index 9e4e6b29d..baf13d4d8 100644
--- a/crates/wasi-http/src/proxy.rs
+++ b/crates/wasi-http/src/proxy.rs
@@ -5,18 +5,8 @@ wasmtime::component::bindgen!({
     tracing: true,
     async: true,
     with: {
-        "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr,
-        "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin,
-        "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout,
-        "wasi:clocks/monotonic-clock": wasmtime_wasi::bindings::clocks::monotonic_clock,
-        "wasi:clocks/timezone": wasmtime_wasi::bindings::clocks::timezone,
-        "wasi:clocks/wall-clock": wasmtime_wasi::bindings::clocks::wall_clock,
-        "wasi:http/incoming-handler": bindings::http::incoming_handler,
-        "wasi:http/outgoing-handler": bindings::http::outgoing_handler,
-        "wasi:http/types": bindings::http::types,
-        "wasi:io/streams": wasmtime_wasi::bindings::io::streams,
-        "wasi:io/poll": wasmtime_wasi::bindings::io::poll,
-        "wasi:random/random": wasmtime_wasi::bindings::random::random,
+        "wasi:http": bindings::http,
+        "wasi": wasmtime_wasi::bindings,
     },
 });
 
@@ -56,18 +46,9 @@ pub mod sync {
         tracing: true,
         async: false,
         with: {
-            "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr,
-            "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin,
-            "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout,
-            "wasi:clocks/monotonic-clock": wasmtime_wasi::bindings::clocks::monotonic_clock,
-            "wasi:clocks/timezone": wasmtime_wasi::bindings::clocks::timezone,
-            "wasi:clocks/wall-clock": wasmtime_wasi::bindings::clocks::wall_clock,
-            "wasi:http/incoming-handler": bindings::http::incoming_handler,
-            "wasi:http/outgoing-handler": bindings::http::outgoing_handler,
-            "wasi:http/types": bindings::http::types,
-            "wasi:io/streams": wasmtime_wasi::bindings::io::streams,
-            "wasi:poll/poll": wasmtime_wasi::bindings::poll::poll,
-            "wasi:random/random": wasmtime_wasi::bindings::random::random,
+            "wasi:http": bindings::http, // http is in this crate
+            "wasi:io": wasmtime_wasi::bindings::sync_io, // io is sync
+            "wasi": wasmtime_wasi::bindings, // everything else
         },
     });
 
diff --git a/crates/wasi/src/bindings.rs b/crates/wasi/src/bindings.rs
index 034aaa92d..a313326da 100644
--- a/crates/wasi/src/bindings.rs
+++ b/crates/wasi/src/bindings.rs
@@ -19,7 +19,13 @@ pub mod sync_io {
                 "wasi:filesystem/types/error-code" => FsError,
             },
             with: {
-                "wasi:clocks/wall-clock": crate::bindings::clocks::wall_clock,
+                // This interface comes from the outer module, as it's
+                // sync/async agnostic.
+                "wasi:clocks": crate::bindings::clocks,
+
+                // Configure the resource types of the bound interfaces here
+                // to be the same as the async versions of the resources, that
+                // way everything has the same type.
                 "wasi:filesystem/types/descriptor": super::super::filesystem::types::Descriptor,
                 "wasi:filesystem/types/directory-entry-stream": super::super::filesystem::types::DirectoryEntryStream,
                 "wasi:io/poll/pollable": super::super::io::poll::Pollable,
@@ -100,6 +106,9 @@ wasmtime::component::bindgen!({
         "wasi:sockets/network/error-code" => crate::SocketError,
     },
     with: {
+        // Configure all resources to be concrete types defined in this crate,
+        // so that way we get to use nice typed helper methods with
+        // `ResourceTable`.
         "wasi:sockets/network/network": super::network::Network,
         "wasi:sockets/tcp/tcp-socket": super::tcp::TcpSocket,
         "wasi:sockets/udp/udp-socket": super::udp::UdpSocket,
diff --git a/crates/wasi/src/command.rs b/crates/wasi/src/command.rs
index 2638ca103..57ccd7be6 100644
--- a/crates/wasi/src/command.rs
+++ b/crates/wasi/src/command.rs
@@ -4,26 +4,7 @@ wasmtime::component::bindgen!({
     world: "wasi:cli/command",
     tracing: true,
     async: true,
-    with: {
-       "wasi:filesystem/types": crate::bindings::filesystem::types,
-       "wasi:filesystem/preopens": crate::bindings::filesystem::preopens,
-       "wasi:sockets/tcp": crate::bindings::sockets::tcp,
-       "wasi:clocks/monotonic_clock": crate::bindings::clocks::monotonic_clock,
-       "wasi:io/poll": crate::bindings::io::poll,
-       "wasi:io/streams": crate::bindings::io::streams,
-       "wasi:clocks/wall_clock": crate::bindings::clocks::wall_clock,
-       "wasi:random/random": crate::bindings::random::random,
-       "wasi:cli/environment": crate::bindings::cli::environment,
-       "wasi:cli/exit": crate::bindings::cli::exit,
-       "wasi:cli/stdin": crate::bindings::cli::stdin,
-       "wasi:cli/stdout": crate::bindings::cli::stdout,
-       "wasi:cli/stderr": crate::bindings::cli::stderr,
-       "wasi:cli/terminal-input": crate::bindings::cli::terminal_input,
-       "wasi:cli/terminal-output": crate::bindings::cli::terminal_output,
-       "wasi:cli/terminal-stdin": crate::bindings::cli::terminal_stdin,
-       "wasi:cli/terminal-stdout": crate::bindings::cli::terminal_stdout,
-       "wasi:cli/terminal-stderr": crate::bindings::cli::terminal_stderr,
-    },
+    with: { "wasi": crate::bindings },
 });
 
 pub fn add_to_linker<T: WasiView>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Result<()> {
@@ -65,25 +46,14 @@ pub mod sync {
         tracing: true,
         async: false,
         with: {
-           "wasi:filesystem/types": crate::bindings::sync_io::filesystem::types,
-           "wasi:filesystem/preopens": crate::bindings::filesystem::preopens,
-           "wasi:sockets/tcp": crate::bindings::sockets::tcp,
-           "wasi:sockets/udp": crate::bindings::sockets::udp,
-           "wasi:clocks/monotonic_clock": crate::bindings::clocks::monotonic_clock,
-           "wasi:io/poll": crate::bindings::sync_io::io::poll,
-           "wasi:io/streams": crate::bindings::sync_io::io::streams,
-           "wasi:clocks/wall_clock": crate::bindings::clocks::wall_clock,
-           "wasi:random/random": crate::bindings::random::random,
-           "wasi:cli/environment": crate::bindings::cli::environment,
-           "wasi:cli/exit": crate::bindings::cli::exit,
-           "wasi:cli/stdin": crate::bindings::cli::stdin,
-           "wasi:cli/stdout": crate::bindings::cli::stdout,
-           "wasi:cli/stderr": crate::bindings::cli::stderr,
-           "wasi:cli/terminal-input": crate::bindings::cli::terminal_input,
-           "wasi:cli/terminal-output": crate::bindings::cli::terminal_output,
-           "wasi:cli/terminal-stdin": crate::bindings::cli::terminal_stdin,
-           "wasi:cli/terminal-stdout": crate::bindings::cli::terminal_stdout,
-           "wasi:cli/terminal-stderr": crate::bindings::cli::terminal_stderr,
+            // Map interfaces with synchronous funtions to their synchronous
+            // counterparts...
+            "wasi:filesystem": crate::bindings::sync_io::filesystem,
+            "wasi:io": crate::bindings::sync_io::io,
+
+            // ... and everything else is not-async and so goes through the
+            // top-level bindings.
+            "wasi": crate::bindings
         },
     });
 
diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs
index 7247b93a1..b9f81350c 100644
--- a/crates/wasmtime/src/runtime/component/mod.rs
+++ b/crates/wasmtime/src/runtime/component/mod.rs
@@ -414,7 +414,25 @@ pub(crate) use self::store::ComponentStoreData;
 ///     // with an invocation of this macro. Resources need to be mapped to a
 ///     // Rust type name.
 ///     with: {
-///         "wasi:random/random": some::other::wasi::random::random,
+///         // This can be used to indicate that entire interfaces have
+///         // bindings generated elsewhere with a path pointing to the
+///         // bindinges-generated module.
+///         "wasi:random/random": wasmtime_wasi::bindings::random::random,
+///
+///         // Similarly entire packages can also be specified.
+///         "wasi:cli": wasmtime_wasi::bindings::cli,
+///
+///         // Or, if applicable, entire namespaces can additionally be mapped.
+///         "wasi": wasmtime_wasi::bindings,
+///
+///         // Versions are supported if multiple versions are in play:
+///         "wasi:http/types@0.2.0": wasmtime_wasi_http::bindings::http::types,
+///         "wasi:http@0.2.0": wasmtime_wasi_http::bindings::http,
+///
+///         // The `with` key can also be used to specify the `T` used in
+///         // import bindings of `Resource<T>`. This can be done to configure
+///         // which typed resource shows up in generated bindings and can be
+///         // useful when working with the typed methods of `ResourceTable`.
 ///         "wasi:filesystem/types/descriptor": MyDescriptorType,
 ///     },
 /// });
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 7042eb7f0..2f92db841 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -48,7 +48,6 @@ struct Wasmtime {
     types: Types,
     sizes: SizeAlign,
     interface_names: HashMap<InterfaceId, InterfaceName>,
-    with_name_counter: usize,
     interface_last_seen_as_import: HashMap<InterfaceId, bool>,
     trappable_errors: IndexMap<TypeId, String>,
 }
@@ -188,13 +187,9 @@ impl Wasmtime {
                 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
             }
         }
-        let entry = if let Some(remapped_path) = self.lookup_replacement(resolve, name, None) {
-            let remapped_path = remapped_path.to_string();
-            let name = format!("__with_name{}", self.with_name_counter);
-            self.with_name_counter += 1;
-            uwriteln!(self.src, "use {remapped_path} as {name};");
+        let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) {
             InterfaceName::Remapped {
-                name_at_root: name,
+                name_at_root,
                 local_path: path,
             }
         } else {
@@ -263,6 +258,18 @@ impl Wasmtime {
             assert!(prev.is_none());
         }
 
+        // Convert all entries in `with` as relative to the root of where the
+        // macro itself is invoked. This emits a `pub use` to bring the name
+        // into scope under an "anonymous name" which then replaces the `with`
+        // map entry.
+        let mut with = self.opts.with.iter_mut().collect::<Vec<_>>();
+        with.sort();
+        for (i, (_k, v)) in with.into_iter().enumerate() {
+            let name = format!("__with_name{i}");
+            uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};");
+            *v = name;
+        }
+
         let world = &resolve.worlds[id];
         for (name, import) in world.imports.iter() {
             if !self.opts.only_interfaces || matches!(import, WorldItem::Interface(_)) {
@@ -666,42 +673,144 @@ impl Wasmtime {
         }
     }
 
+    /// Attempts to find the `key`, possibly with the resource projection
+    /// `item`, within the `with` map provided to bindings configuration.
     fn lookup_replacement(
         &self,
         resolve: &Resolve,
         key: &WorldKey,
         item: Option<&str>,
-    ) -> Option<&str> {
-        // First try to lookup the exact name of the interface as specified
-        // via `name_world_key`.
-        let name = resolve.name_world_key(key);
-        let candidate1 = match item {
-            Some(item) => format!("{name}/{item}"),
-            None => name.clone(),
+    ) -> Option<String> {
+        struct Name<'a> {
+            prefix: Prefix,
+            item: Option<&'a str>,
+        }
+
+        #[derive(Copy, Clone)]
+        enum Prefix {
+            Namespace(PackageId),
+            UnversionedPackage(PackageId),
+            VersionedPackage(PackageId),
+            UnversionedInterface(InterfaceId),
+            VersionedInterface(InterfaceId),
+        }
+
+        let prefix = match key {
+            WorldKey::Interface(id) => Prefix::VersionedInterface(*id),
+
+            // Non-interface-keyed names don't get the lookup logic below,
+            // they're relatively uncommon so only lookup the precise key here.
+            WorldKey::Name(key) => {
+                let to_lookup = match item {
+                    Some(item) => format!("{key}/{item}"),
+                    None => key.to_string(),
+                };
+                return self.opts.with.get(&to_lookup).cloned();
+            }
         };
-        if let Some(ret) = self.opts.with.get(&candidate1) {
-            return Some(ret);
-        }
 
-        // .. if the above failed allow omitting the `@...` version information
-        // and see if there's a `with` key for that.
+        // Here names are iteratively attempted as `key` + `item` is "walked to
+        // its root" and each attempt is consulted in `self.opts.with`. This
+        // loop will start at the leaf, the most specific path, and then walk to
+        // the root, popping items, trying to find a result.
         //
-        // NB: this means that in a scenario where there's packages with the
-        // same name/namespace where one has a version and one doesn't there's
-        // no way to use `with` to specify just one and not the other. That
-        // should be ok for now, but this should ideally detect a situation like
-        // that and omit this fallback in such a situation.
-        let version_start = name.find('@')?;
-        let name = &name[..version_start];
-        let candidate2 = match item {
-            Some(item) => format!("{name}/{item}"),
-            None => name.to_string(),
-        };
-        if let Some(ret) = self.opts.with.get(&candidate2) {
-            return Some(ret);
+        // Each time a name is "popped" the projection from the next path is
+        // pushed onto `projection`. This means that if we actually find a match
+        // then `projection` is a collection of namespaces that results in the
+        // final replacement name.
+        let mut name = Name { prefix, item };
+        let mut projection = Vec::new();
+        loop {
+            let lookup = name.lookup_key(resolve);
+            if let Some(renamed) = self.opts.with.get(&lookup) {
+                projection.push(renamed.clone());
+                projection.reverse();
+                return Some(projection.join("::"));
+            }
+            if !name.pop(resolve, &mut projection) {
+                return None;
+            }
+        }
+
+        impl<'a> Name<'a> {
+            fn lookup_key(&self, resolve: &Resolve) -> String {
+                let mut s = self.prefix.lookup_key(resolve);
+                if let Some(item) = self.item {
+                    s.push_str("/");
+                    s.push_str(item);
+                }
+                s
+            }
+
+            fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool {
+                match (self.item, self.prefix) {
+                    // If this is a versioned resource name, try the unversioned
+                    // resource name next.
+                    (Some(_), Prefix::VersionedInterface(id)) => {
+                        self.prefix = Prefix::UnversionedInterface(id);
+                        true
+                    }
+                    // If this is an unversioned resource name then time to
+                    // ignore the resource itself and move on to the next most
+                    // specific item, versioned interface names.
+                    (Some(item), Prefix::UnversionedInterface(id)) => {
+                        self.prefix = Prefix::VersionedInterface(id);
+                        self.item = None;
+                        projection.push(item.to_upper_camel_case());
+                        true
+                    }
+                    (Some(_), _) => unreachable!(),
+                    (None, _) => self.prefix.pop(resolve, projection),
+                }
+            }
         }
 
-        None
+        impl Prefix {
+            fn lookup_key(&self, resolve: &Resolve) -> String {
+                match *self {
+                    Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(),
+                    Prefix::UnversionedPackage(id) => {
+                        let mut name = resolve.packages[id].name.clone();
+                        name.version = None;
+                        name.to_string()
+                    }
+                    Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(),
+                    Prefix::UnversionedInterface(id) => {
+                        let id = resolve.id_of(id).unwrap();
+                        match id.find('@') {
+                            Some(i) => id[..i].to_string(),
+                            None => id,
+                        }
+                    }
+                    Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(),
+                }
+            }
+
+            fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool {
+                *self = match *self {
+                    // try the unversioned interface next
+                    Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id),
+                    // try this interface's versioned package next
+                    Prefix::UnversionedInterface(id) => {
+                        let iface = &resolve.interfaces[id];
+                        let name = iface.name.as_ref().unwrap();
+                        projection.push(to_rust_ident(name));
+                        Prefix::VersionedPackage(iface.package.unwrap())
+                    }
+                    // try the unversioned package next
+                    Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id),
+                    // try this package's namespace next
+                    Prefix::UnversionedPackage(id) => {
+                        let name = &resolve.packages[id].name;
+                        projection.push(to_rust_ident(&name.name));
+                        Prefix::Namespace(id)
+                    }
+                    // nothing left to try any more
+                    Prefix::Namespace(_) => return false,
+                };
+                true
+            }
+        }
     }
 }
 
@@ -960,7 +1069,7 @@ impl<'a> InterfaceGenerator<'a> {
 
             let replacement = match self.current_interface {
                 Some((_, key, _)) => self.gen.lookup_replacement(self.resolve, key, Some(name)),
-                None => self.gen.opts.with.get(name).map(|s| s.as_str()),
+                None => self.gen.opts.with.get(name).cloned(),
             };
             match replacement {
                 Some(path) => {
diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml
index 5f6db2f7b..f37438171 100644
--- a/supply-chain/audits.toml
+++ b/supply-chain/audits.toml
@@ -3739,6 +3739,12 @@ user-id = 73222 # wasmtime-publish
 start = "2024-02-23"
 end = "2025-02-23"
 
+[[trusted.wit-bindgen-rt]]
+criteria = "safe-to-deploy"
+user-id = 73222 # wasmtime-publish
+start = "2024-03-04"
+end = "2025-03-11"
+
 [[trusted.wit-bindgen-rust]]
 criteria = "safe-to-deploy"
 user-id = 73222 # wasmtime-publish
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 3a2bea9a3..622fa6e93 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -1886,6 +1886,12 @@ when = "2024-02-29"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-bindgen]]
+version = "0.22.0"
+when = "2024-03-11"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wit-bindgen-core]]
 version = "0.17.0"
 when = "2024-02-05"
@@ -1911,6 +1917,18 @@ when = "2024-02-29"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-bindgen-core]]
+version = "0.22.0"
+when = "2024-03-11"
+user-id = 73222
+user-login = "wasmtime-publish"
+
+[[publisher.wit-bindgen-rt]]
+version = "0.22.0"
+when = "2024-03-11"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wit-bindgen-rust]]
 version = "0.17.0"
 when = "2024-02-05"
@@ -1936,6 +1954,12 @@ when = "2024-02-29"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-bindgen-rust]]
+version = "0.22.0"
+when = "2024-03-11"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wit-bindgen-rust-macro]]
 version = "0.17.0"
 when = "2024-02-05"
@@ -1961,6 +1985,12 @@ when = "2024-02-29"
 user-id = 73222
 user-login = "wasmtime-publish"
 
+[[publisher.wit-bindgen-rust-macro]]
+version = "0.22.0"
+when = "2024-03-11"
+user-id = 73222
+user-login = "wasmtime-publish"
+
 [[publisher.wit-component]]
 version = "0.20.1"
 when = "2024-01-29"


Test patch:
diff --git a/cranelift/filetests/filetests/isa/x64/fcvt-avx.clif b/cranelift/filetests/filetests/isa/x64/fcvt-avx.clif
index 5d72e1090..61f7f0ec3 100644
--- a/cranelift/filetests/filetests/isa/x64/fcvt-avx.clif
+++ b/cranelift/filetests/filetests/isa/x64/fcvt-avx.clif
@@ -155,3 +155,41 @@ block0(v0: i64x2):
 ;   addb %al, (%rax)
 ;   addb %al, (%rax)
 
+function %i64x2_to_f64x2(i64x2) -> f64x2 {
+block0(v0: i64x2):
+  v1 = fcvt_from_sint.f64x2 v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   uninit  %xmm2
+;   vxorpd  %xmm2, %xmm2, %xmm4
+;   vmovq   %xmm0, %r9
+;   vcvtsi2sd %xmm4, %r9, %xmm1
+;   vpshufd $238, %xmm0, %xmm2
+;   vmovq   %xmm2, %rcx
+;   vcvtsi2sd %xmm4, %rcx, %xmm6
+;   vunpcklpd %xmm1, %xmm6, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   vxorpd %xmm2, %xmm2, %xmm4
+;   vmovq %xmm0, %r9
+;   vcvtsi2sdq %r9, %xmm4, %xmm1
+;   vpshufd $0xee, %xmm0, %xmm2
+;   vmovq %xmm2, %rcx
+;   vcvtsi2sdq %rcx, %xmm4, %xmm6
+;   vunpcklpd %xmm6, %xmm1, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/isa/x64/fcvt.clif b/cranelift/filetests/filetests/isa/x64/fcvt.clif
index 882d253e3..ae506aa09 100644
--- a/cranelift/filetests/filetests/isa/x64/fcvt.clif
+++ b/cranelift/filetests/filetests/isa/x64/fcvt.clif
@@ -1196,3 +1196,45 @@ block0(v0: i64x2):
 ;   addb %al, (%rax)
 ;   addb %al, (%rax)
 
+function %i64x2_to_f64x2(i64x2) -> f64x2 {
+block0(v0: i64x2):
+  v1 = fcvt_from_sint.f64x2 v0
+  return v1
+}
+
+; VCode:
+;   pushq   %rbp
+;   movq    %rsp, %rbp
+; block0:
+;   uninit  %xmm1
+;   xorpd   %xmm1, %xmm1, %xmm1
+;   movdqa  %xmm0, %xmm6
+;   movq    %xmm6, %r9
+;   movdqa  %xmm1, %xmm0
+;   cvtsi2sd %xmm0, %r9, %xmm0
+;   pshufd  $238, %xmm6, %xmm2
+;   movq    %xmm2, %rcx
+;   cvtsi2sd %xmm1, %rcx, %xmm1
+;   unpcklpd %xmm0, %xmm1, %xmm0
+;   movq    %rbp, %rsp
+;   popq    %rbp
+;   ret
+;
+; Disassembled:
+; block0: ; offset 0x0
+;   pushq %rbp
+;   movq %rsp, %rbp
+; block1: ; offset 0x4
+;   xorpd %xmm1, %xmm1
+;   movdqa %xmm0, %xmm6
+;   movq %xmm6, %r9
+;   movdqa %xmm1, %xmm0
+;   cvtsi2sdq %r9, %xmm0
+;   pshufd $0xee, %xmm6, %xmm2
+;   movq %xmm2, %rcx
+;   cvtsi2sdq %rcx, %xmm1
+;   unpcklpd %xmm1, %xmm0
+;   movq %rbp, %rsp
+;   popq %rbp
+;   retq
+
diff --git a/cranelift/filetests/filetests/runtests/simd-fcvt-from-sint.clif b/cranelift/filetests/filetests/runtests/simd-fcvt-from-sint.clif
index f7e2e6571..d5f86eb2d 100644
--- a/cranelift/filetests/filetests/runtests/simd-fcvt-from-sint.clif
+++ b/cranelift/filetests/filetests/runtests/simd-fcvt-from-sint.clif
@@ -9,10 +9,18 @@ target x86_64 sse42 has_avx
 target riscv64 has_v
 target riscv64 has_v has_c has_zcb
 
-function %fcvt_from_sint(i32x4) -> f32x4 {
+function %fcvt_from_sint32(i32x4) -> f32x4 {
 block0(v0: i32x4):
     v1 = fcvt_from_sint.f32x4 v0
     return v1
 }
-; run: %fcvt_from_sint([-1 0 1 123456789]) == [-0x1.0 0.0 0x1.0 0x75bcd18.0]
+; run: %fcvt_from_sint32([-1 0 1 123456789]) == [-0x1.0 0.0 0x1.0 0x75bcd18.0]
 ; Note that 123456789 rounds to 123456792.0, an error of 3
+
+function %fcvt_from_sint64(i64x2) -> f64x2 {
+block0(v0: i64x2):
+    v1 = fcvt_from_sint.f64x2 v0
+    return v1
+}
+; run: %fcvt_from_sint64([-1 0]) == [-0x1.0 0.0]
+; run: %fcvt_from_sint64([1 123456789]) == [0x1.0 0x75bcd15.0]
diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs
index c7fb0f51a..da2f0550d 100644
--- a/crates/component-macro/tests/codegen.rs
+++ b/crates/component-macro/tests/codegen.rs
@@ -162,3 +162,154 @@ mod interface_name_with_rust_keyword {
         "
     });
 }
+
+mod with_works_with_hierarchy {
+    mod bindings {
+        wasmtime::component::bindgen!({
+            inline: "
+                package foo:foo;
+
+                interface a {
+                    record t {
+                        x: u32,
+                    }
+                    x: func() -> t;
+                }
+
+                interface b {
+                    use a.{t};
+                    x: func() -> t;
+                }
+
+                interface c {
+                    use b.{t};
+                    x: func() -> t;
+                }
+
+                world foo {
+                    import c;
+                }
+            "
+        });
+    }
+
+    mod with_just_one_interface {
+        wasmtime::component::bindgen!({
+            inline: "
+                package foo:foo;
+
+                interface a {
+                    record t {
+                        x: u32,
+                    }
+                    x: func() -> t;
+                }
+
+                interface b {
+                    use a.{t};
+                    x: func() -> t;
+                }
+
+                interface c {
+                    use b.{t};
+                    x: func() -> t;
+                }
+
+                world foo {
+                    use c.{t};
+
+                    import x: func() -> t;
+                }
+            ",
+            with: { "foo:foo/a": super::bindings::foo::foo::a }
+        });
+
+        struct X;
+
+        impl FooImports for X {
+            fn x(&mut self) -> wasmtime::Result<super::bindings::foo::foo::a::T> {
+                loop {}
+            }
+        }
+    }
+
+    mod with_whole_package {
+        wasmtime::component::bindgen!({
+            inline: "
+                package foo:foo;
+
+                interface a {
+                    record t {
+                        x: u32,
+                    }
+                    x: func() -> t;
+                }
+
+                interface b {
+                    use a.{t};
+                    x: func() -> t;
+                }
+
+                interface c {
+                    use b.{t};
+                    x: func() -> t;
+                }
+
+                world foo {
+                    use c.{t};
+
+                    import x: func() -> t;
+                }
+            ",
+            with: { "foo:foo": super::bindings::foo::foo }
+        });
+
+        struct X;
+
+        impl FooImports for X {
+            fn x(&mut self) -> wasmtime::Result<super::bindings::foo::foo::a::T> {
+                loop {}
+            }
+        }
+    }
+
+    mod with_whole_namespace {
+        wasmtime::component::bindgen!({
+            inline: "
+                package foo:foo;
+
+                interface a {
+                    record t {
+                        x: u32,
+                    }
+                    x: func() -> t;
+                }
+
+                interface b {
+                    use a.{t};
+                    x: func() -> t;
+                }
+
+                interface c {
+                    use b.{t};
+                    x: func() -> t;
+                }
+
+                world foo {
+                    use c.{t};
+
+                    import x: func() -> t;
+                }
+            ",
+            with: { "foo": super::bindings::foo }
+        });
+
+        struct X;
+
+        impl FooImports for X {
+            fn x(&mut self) -> wasmtime::Result<super::bindings::foo::foo::a::T> {
+                loop {}
+            }
+        }
+    }
+}
diff --git a/crates/wasi/tests/all/api.rs b/crates/wasi/tests/all/api.rs
index 2fc594697..80c93b8d7 100644
--- a/crates/wasi/tests/all/api.rs
+++ b/crates/wasi/tests/all/api.rs
@@ -125,21 +125,7 @@ fn api_proxy_streaming() {}
 wasmtime::component::bindgen!({
     world: "test-reactor",
     async: true,
-    with: {
-       "wasi:io/streams": wasmtime_wasi::bindings::io::streams,
-       "wasi:filesystem/types": wasmtime_wasi::bindings::filesystem::types,
-       "wasi:filesystem/preopens": wasmtime_wasi::bindings::filesystem::preopens,
-       "wasi:cli/environment": wasmtime_wasi::bindings::cli::environment,
-       "wasi:cli/exit": wasmtime_wasi::bindings::cli::exit,
-       "wasi:cli/stdin": wasmtime_wasi::bindings::cli::stdin,
-       "wasi:cli/stdout": wasmtime_wasi::bindings::cli::stdout,
-       "wasi:cli/stderr": wasmtime_wasi::bindings::cli::stderr,
-       "wasi:cli/terminal_input": wasmtime_wasi::bindings::cli::terminal_input,
-       "wasi:cli/terminal_output": wasmtime_wasi::bindings::cli::terminal_output,
-       "wasi:cli/terminal_stdin": wasmtime_wasi::bindings::cli::terminal_stdin,
-       "wasi:cli/terminal_stdout": wasmtime_wasi::bindings::cli::terminal_stdout,
-       "wasi:cli/terminal_stderr": wasmtime_wasi::bindings::cli::terminal_stderr,
-    },
+    with: { "wasi": wasmtime_wasi::bindings },
     ownership: Borrowing {
         duplicate_if_necessary: false
     }