Bug 1582650 - Cranelift: update version to 0.44, rev to 182414f15c18538dfebbe040469ec8001e93ecc5. r=bbouvier.
authorJulian Seward <jseward@acm.org>
Thu, 26 Sep 2019 09:40:11 +0000
changeset 495075 7984123ec4f76cd753eaf6f3cff1bea3aa4878b9
parent 495074 9c7b5d473fe9f83d630f8d38af8253e347580ff1
child 495076 59801043fb2954369d5fc80f5ee617d2b948d1d6
push id36622
push usershindli@mozilla.com
push dateThu, 26 Sep 2019 21:35:42 +0000
treeherdermozilla-central@1d189ae70326 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1582650
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1582650 - Cranelift: update version to 0.44, rev to 182414f15c18538dfebbe040469ec8001e93ecc5. r=bbouvier. Depends on D47206 Differential Revision: https://phabricator.services.mozilla.com/D47207
.cargo/config.in
Cargo.lock
Cargo.toml
js/src/wasm/cranelift/Cargo.toml
third_party/rust/cranelift-bforest/.cargo-checksum.json
third_party/rust/cranelift-bforest/Cargo.toml
third_party/rust/cranelift-bforest/src/pool.rs
third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
third_party/rust/cranelift-codegen-meta/Cargo.toml
third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/cpu_modes.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/encodings.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs
third_party/rust/cranelift-codegen-meta/src/constant_hash.rs
third_party/rust/cranelift-codegen-meta/src/default_map.rs
third_party/rust/cranelift-codegen-meta/src/gen_binemit.rs
third_party/rust/cranelift-codegen-meta/src/gen_inst.rs
third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs
third_party/rust/cranelift-codegen-meta/src/gen_registers.rs
third_party/rust/cranelift-codegen-meta/src/gen_settings.rs
third_party/rust/cranelift-codegen-meta/src/gen_types.rs
third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/opcodes.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs
third_party/rust/cranelift-codegen-meta/src/shared/formats.rs
third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs
third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs
third_party/rust/cranelift-codegen-meta/src/shared/mod.rs
third_party/rust/cranelift-codegen-meta/src/shared/settings.rs
third_party/rust/cranelift-codegen-shared/.cargo-checksum.json
third_party/rust/cranelift-codegen-shared/Cargo.toml
third_party/rust/cranelift-codegen-shared/LICENSE
third_party/rust/cranelift-codegen-shared/README.md
third_party/rust/cranelift-codegen-shared/src/condcodes.rs
third_party/rust/cranelift-codegen-shared/src/lib.rs
third_party/rust/cranelift-codegen/.cargo-checksum.json
third_party/rust/cranelift-codegen/Cargo.toml
third_party/rust/cranelift-codegen/src/binemit/stackmap.rs
third_party/rust/cranelift-codegen/src/context.rs
third_party/rust/cranelift-codegen/src/ir/condcodes.rs
third_party/rust/cranelift-codegen/src/ir/dfg.rs
third_party/rust/cranelift-codegen/src/ir/entities.rs
third_party/rust/cranelift-codegen/src/ir/immediates.rs
third_party/rust/cranelift-codegen/src/ir/instructions.rs
third_party/rust/cranelift-codegen/src/ir/layout.rs
third_party/rust/cranelift-codegen/src/ir/mod.rs
third_party/rust/cranelift-codegen/src/ir/trapcode.rs
third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
third_party/rust/cranelift-codegen/src/isa/mod.rs
third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
third_party/rust/cranelift-codegen/src/legalizer/heap.rs
third_party/rust/cranelift-codegen/src/lib.rs
third_party/rust/cranelift-codegen/src/predicates.rs
third_party/rust/cranelift-codegen/src/ref_slice.rs
third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
third_party/rust/cranelift-codegen/src/regalloc/live_value_tracker.rs
third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
third_party/rust/cranelift-codegen/src/regalloc/liverange.rs
third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs
third_party/rust/cranelift-codegen/src/settings.rs
third_party/rust/cranelift-codegen/src/topo_order.rs
third_party/rust/cranelift-codegen/src/value_label.rs
third_party/rust/cranelift-codegen/src/verifier/cssa.rs
third_party/rust/cranelift-codegen/src/verifier/flags.rs
third_party/rust/cranelift-codegen/src/verifier/liveness.rs
third_party/rust/cranelift-codegen/src/verifier/locations.rs
third_party/rust/cranelift-codegen/src/verifier/mod.rs
third_party/rust/cranelift-codegen/src/write.rs
third_party/rust/cranelift-entity/.cargo-checksum.json
third_party/rust/cranelift-entity/Cargo.toml
third_party/rust/cranelift-entity/src/set.rs
third_party/rust/cranelift-frontend/.cargo-checksum.json
third_party/rust/cranelift-frontend/Cargo.toml
third_party/rust/cranelift-wasm/.cargo-checksum.json
third_party/rust/cranelift-wasm/Cargo.toml
third_party/rust/cranelift-wasm/src/code_translator.rs
third_party/rust/cranelift-wasm/src/environ/spec.rs
third_party/rust/cranelift-wasm/src/func_translator.rs
third_party/rust/cranelift-wasm/src/lib.rs
third_party/rust/cranelift-wasm/src/module_translator.rs
third_party/rust/cranelift-wasm/src/sections_translator.rs
third_party/rust/cranelift-wasm/src/state.rs
third_party/rust/cranelift-wasm/src/translation_utils.rs
third_party/rust/wasmparser/.cargo-checksum.json
third_party/rust/wasmparser/Cargo.lock
third_party/rust/wasmparser/Cargo.toml
third_party/rust/wasmparser/README.md
third_party/rust/wasmparser/src/lib.rs
third_party/rust/wasmparser/src/operators_validator.rs
third_party/rust/wasmparser/src/primitives.rs
third_party/rust/wasmparser/src/readers/mod.rs
third_party/rust/wasmparser/src/readers/module.rs
third_party/rust/wasmparser/src/tests.rs
third_party/rust/wasmparser/src/validator.rs
--- a/.cargo/config.in
+++ b/.cargo/config.in
@@ -20,17 +20,17 @@ replace-with = "vendored-sources"
 [source."https://github.com/NikVolf/tokio-named-pipes"]
 branch = "stable"
 git = "https://github.com/NikVolf/tokio-named-pipes"
 replace-with = "vendored-sources"
 
 [source."https://github.com/CraneStation/Cranelift"]
 git = "https://github.com/CraneStation/Cranelift"
 replace-with = "vendored-sources"
-rev = "9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
+rev = "182414f15c18538dfebbe040469ec8001e93ecc5"
 
 [source.crates-io]
 replace-with = "vendored-sources"
 
 # Take advantage of the fact that cargo will treat lines starting with #
 # as comments to add preprocessing directives. This file can thus by copied
 # as-is to $topsrcdir/.cargo/config with no preprocessing to be used there
 # (for e.g. independent tasks building rust code), or be preprocessed by
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -184,18 +184,18 @@ dependencies = [
  "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "baldrdash"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.51.1-oldsyn (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
- "cranelift-wasm 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
+ "cranelift-codegen 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-wasm 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
  "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "base64"
 version = "0.10.1"
@@ -582,73 +582,80 @@ name = "cose-c"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
-dependencies = [
- "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
+dependencies = [
+ "cranelift-entity 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
-dependencies = [
- "cranelift-bforest 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
- "cranelift-codegen-meta 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
- "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
+dependencies = [
+ "cranelift-bforest 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-codegen-meta 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-codegen-shared 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-entity 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
-dependencies = [
- "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
-]
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
+dependencies = [
+ "cranelift-codegen-shared 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-entity 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+]
+
+[[package]]
+name = "cranelift-codegen-shared"
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
-dependencies = [
- "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
+dependencies = [
+ "cranelift-codegen 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.42.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e#9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
-dependencies = [
- "cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
- "cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
- "cranelift-frontend 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)",
+version = "0.44.0"
+source = "git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5#182414f15c18538dfebbe040469ec8001e93ecc5"
+dependencies = [
+ "cranelift-codegen 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-entity 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
+ "cranelift-frontend 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasmparser 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "crc32fast"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3454,17 +3461,17 @@ dependencies = [
  "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "urlencoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "wasmparser"
-version = "0.37.0"
+version = "0.39.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "webdriver"
 version = "0.40.2"
 dependencies = [
  "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3798,22 +3805,23 @@ dependencies = [
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 "checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
 "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
 "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
 "checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
 "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
 "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
 "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
-"checksum cranelift-bforest 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
-"checksum cranelift-codegen 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
-"checksum cranelift-codegen-meta 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
-"checksum cranelift-entity 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
-"checksum cranelift-frontend 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
-"checksum cranelift-wasm 0.42.0 (git+https://github.com/CraneStation/Cranelift?rev=9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e)" = "<none>"
+"checksum cranelift-bforest 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-codegen 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-codegen-meta 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-codegen-shared 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-entity 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-frontend 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
+"checksum cranelift-wasm 0.44.0 (git+https://github.com/CraneStation/Cranelift?rev=182414f15c18538dfebbe040469ec8001e93ecc5)" = "<none>"
 "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
 "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
 "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
 "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
 "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
 "checksum cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a921abc45ea75c2c817d951caeda31b94539d09a6b5e8d58a857b3b35c9c3894"
 "checksum cssparser-macros 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b16e382d9b983fdb9ac6a36b37fdeb84ce3ea81f749febfee3463cfa7f24275e"
 "checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
@@ -4054,17 +4062,17 @@ dependencies = [
 "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
 "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
 "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
 "checksum warp 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "33857527c63bc514452f885d0a57019f28139c58fef2b3566016ecc0d44e5d24"
-"checksum wasmparser 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82dbea680995dad585289fd47889cf9614133ebfcc3bda95737ef8bdc9e11db6"
+"checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c"
 "checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -59,16 +59,16 @@ codegen-units = 1
 
 [patch.crates-io]
 libudev-sys = { path = "dom/webauthn/libudev-sys" }
 winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
 packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
 
 [patch.crates-io.cranelift-codegen]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
+rev = "182414f15c18538dfebbe040469ec8001e93ecc5"
 
 [patch.crates-io.cranelift-wasm]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "9c6f8feb0f28f50434c0cf67f3f7c07486a42b7e"
+rev = "182414f15c18538dfebbe040469ec8001e93ecc5"
 
 [patch.crates-io.coreaudio-sys]
 path = "third_party/rust/coreaudio-sys"
--- a/js/src/wasm/cranelift/Cargo.toml
+++ b/js/src/wasm/cranelift/Cargo.toml
@@ -8,18 +8,18 @@ edition = "2018"
 crate-type = ["rlib"]
 name = "baldrdash"
 
 [dependencies]
 # The build system redirects the versions of cranelift-codegen and
 # cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
 # you should update the following $TOP_LEVEL/Cargo.toml file: look for the
 # revision (rev) hashes of both cranelift dependencies (codegen and wasm).
-cranelift-codegen = { version = "0.42", default-features = false }
-cranelift-wasm = "0.42"
+cranelift-codegen = { version = "0.44", default-features = false }
+cranelift-wasm = "0.44"
 log = { version = "0.4.6", default-features = false, features = ["release_max_level_info"] }
 env_logger = "0.6"
 smallvec = { version = "0.6.6" }
 
 [build-dependencies]
 bindgen = {version = "0.51.1-oldsyn", default-features = false} # disable `logging` to reduce code size
 
 [features]
--- a/third_party/rust/cranelift-bforest/.cargo-checksum.json
+++ b/third_party/rust/cranelift-bforest/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"5c0fac24938cd87403f8055d56082b820a284f40a45be73c0fcd63fad0704285","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"d821f2fe04df070a05a2e1de29b913f9970dfb500b35511a39c2976f1f26c977","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"f6af616cc6e55e0ff0a292c52fb8bd5b093345fe5495e67f153dd94da153adab","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"d821f2fe04df070a05a2e1de29b913f9970dfb500b35511a39c2976f1f26c977","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"56f987d338a9419696ffb3ff09a4322a0ec97554eeca255e8c5fae7941e44f57","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-bforest/Cargo.toml
+++ b/third_party/rust/cranelift-bforest/Cargo.toml
@@ -1,23 +1,23 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-bforest"
-version = "0.42.0"
+version = "0.44.0"
 description = "A forest of B+-trees"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://cranelift.readthedocs.io/"
 repository = "https://github.com/CraneStation/cranelift"
 categories = ["no-std"]
 readme = "README.md"
 keywords = ["btree", "forest", "set", "map"]
 edition = "2018"
 
 [dependencies]
-cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false }
+cranelift-entity = { path = "../cranelift-entity", version = "0.44.0", default-features = false }
 
 [features]
 default = ["std"]
 std = ["cranelift-entity/std"]
 core = []
 
 [badges]
 maintenance = { status = "experimental" }
--- a/third_party/rust/cranelift-bforest/src/pool.rs
+++ b/third_party/rust/cranelift-bforest/src/pool.rs
@@ -78,42 +78,44 @@ impl<F: Forest> NodePool<F> {
 #[cfg(test)]
 impl<F: Forest> NodePool<F> {
     /// Verify the consistency of the tree rooted at `node`.
     pub fn verify_tree<C: Comparator<F::Key>>(&self, node: Node, comp: &C)
     where
         NodeData<F>: fmt::Display,
         F::Key: fmt::Display,
     {
-        use crate::entity::SparseSet;
+        use crate::entity::EntitySet;
         use core::borrow::Borrow;
         use core::cmp::Ordering;
         use std::vec::Vec;
 
         // The root node can't be an inner node with just a single sub-tree. It should have been
         // pruned.
         if let NodeData::Inner { size, .. } = self[node] {
             assert!(size > 0, "Root must have more than one sub-tree");
         }
 
-        let mut done = SparseSet::new();
+        let mut done = match self[node] {
+            NodeData::Inner { size, .. } | NodeData::Leaf { size, .. } => {
+                EntitySet::with_capacity(size.into())
+            }
+            _ => EntitySet::new(),
+        };
+
         let mut todo = Vec::new();
 
         // Todo-list entries are:
         // 1. Optional LHS key which must be <= all node entries.
         // 2. The node reference.
         // 3. Optional RHS key which must be > all node entries.
         todo.push((None, node, None));
 
         while let Some((lkey, node, rkey)) = todo.pop() {
-            assert_eq!(
-                done.insert(node),
-                None,
-                "Node appears more than once in tree"
-            );
+            assert!(done.insert(node), "Node appears more than once in tree");
             let mut lower = lkey;
 
             match self[node] {
                 NodeData::Inner { size, keys, tree } => {
                     let size = size as usize;
                     let capacity = tree.len();
                     let keys = &keys[0..size];
 
--- a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"e4a42edddd547e9aff7d2ccc3469f3685ae1eff54cece29d8f4fa1d2e80b063d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"7ff4532bb6c3c4570918cfac54c308f345d6710ad8696aa444503a60d42408a6","src/cdsl/cpu_modes.rs":"7c59ae347d6f9c769d6356fe49c8406934153eefa59d9bf37c182474fcbb9715","src/cdsl/encodings.rs":"da6fa16c95fe4a586c2d00ef4ccf79b4b0f64cd8923b3ca5a5a527da1e799a4f","src/cdsl/formats.rs":"5ed0d689b791d928e51f9608cb139dde7be810ff1dc4e03c58a6fe79e43eeffd","src/cdsl/instructions.rs":"cd1b1c6ccf90a3ba3506859d7bff9f7073a46c11aecf501b7b35af68e76240e2","src/cdsl/isa.rs":"9b6030a935f69b07726d239c23a78d654566785f1fed61ccefdaf7d4f0a97d0e","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"3e70d11c04a123c9d91075e14af6909a885f37a0c2f86df6aca1b337e2994763","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"c576403ca05921d6a416b21e7f5bd5a2219b635ad78ed1139dc8e3363ba61beb","src/cdsl/types.rs":"9f8221b5d3987b30943ba5f168190cb220b59350e9463ca264ecfd663dbbc3a2","src/cdsl/typevar.rs":"2b67b32524cdf783aeb1fcedbf82a33190104e87ed210ca0638cf6bb28eefd98","src/cdsl/xform.rs":"120be9a35b48d4b2c474bca9684c687797045d1d07554f639e1812cda16cc743","src/constant_hash.rs":"66d6f42c1e98cd4dbc95009997dc00256b57c11d2c2d9eac63b33e458c68a56f","src/default_map.rs":"8bbd6f4d9f93ef2126538cda633e6d9c80a5c7dc79b8d5a759c8be1fe2dbc605","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"80c27e9c66d2ac3dc8a41cc545f046bd4297ba6530805539e86461984fd2667d","src/gen_encodings.rs":"bb598d4eeb8e7365a023ebbb4cc0d8c9f57163b4d0d489047f0fcdbe83880adb","src/gen_inst.rs":"c31663699705cb35697dd23ee4f34d2502414a2d2f716b872e47aac1ba56e710","src/gen_legalizer.rs":"0e8ea0810da954d812f9110e900b9ba3830ff81be46c5985e0340e69f75ebbe8","src/gen_registers.rs":"9b581bd79a1370cdc6920ed18e8da84751813a4b1c9697e891bf0da4eceefc0d","src/gen_settings.rs":"765ca86fa735342c1875021c34a92cbc39836ba3ad1c12aa615204372a1f7b61","src/gen_types.rs":"c062eaf3a2ed7368b87213922906107bbaec184fe821184a34dacb4e5b0fc3dc","src/isa/arm32/mod.rs":"5ca444f18d438f879edb857c75e129931067794a669b607350c4ed648fd92520","src/isa/arm64/mod.rs":"9a1acc8533a1c9be332c565f399cf1c9b5a0a85290bf7bcb82b778fc412d5fa5","src/isa/mod.rs":"a728d5063d34a4ac572ad63ff0f458da33703c58cdd901a0c36276f426fbb0d1","src/isa/riscv/encodings.rs":"695159378a75cb143482c401c4e5ffefa28082cbb996e944942ef0cdc3d10db6","src/isa/riscv/mod.rs":"4945ad95284ac157593935722b75f120b4a0e22b133e69a1e9784e6cd3615c0a","src/isa/riscv/recipes.rs":"5cfdc71a3d5640de6ec956eb8eb6a3a85135daa1d6e30d1d6a693b6ad2d12e0e","src/isa/x86/encodings.rs":"886c875d740ba0b4b3d34c2c06eb33e2089a529eba1103bf962452e0bc34c0e5","src/isa/x86/instructions.rs":"c438579d98562e6efb67edf5983ffab26a3c7c2d8b20dccbd2667687031fa7f4","src/isa/x86/legalize.rs":"1f44559eac3e9db307759bbed8db5d15b1166303e3fa3c9c5fb386ad990e32a5","src/isa/x86/mod.rs":"7a3aeebfed131b86244fc4746b3dc42f4968d48cbb23a10214efb0a0d56c94c9","src/isa/x86/recipes.rs":"a9c128c26918eb01b400b78d7eee04a3cc61784b1288d26bd43b4ea7224f2a82","src/isa/x86/registers.rs":"3cde7d3275971d651ae0f25c88bfb81128b7a35183a969aed81776d4c5141e0e","src/isa/x86/settings.rs":"4e84ff135d6f21595bbd8f56d2e561abd3c123566f2332ac93bb4a9c627f0c00","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"d3dc9d6cb5ba30b1bbdcbfa4505e4897618064dab0b99006fd247d0c93f0b3dc","src/shared/formats.rs":"c6a4622fad932aadb7b5341aee5453c53ff08e0f1e1ee848752cf217fbce62b1","src/shared/immediates.rs":"954ef3c5724f26d16178fc2539111e5ecabebe9ea83d24b2b90d5a8ab411c1a9","src/shared/instructions.rs":"a21d36e9917d7d67c188a46c744c38011d81e892d7a5d32a22437047aecebdbf","src/shared/legalize.rs":"07c6a74ced50bcd7e06731165ede44880c418da0d9785e6e6b8fc02cea218d84","src/shared/mod.rs":"6c9010c934e85c668e089fded99805e9a3aa09a9d9ad408382c5345b6cb375b6","src/shared/settings.rs":"22825dd2b9d924ec147c675836ac3644adffd6a059c31b9470581c4597905c28","src/shared/types.rs":"b47799d381f3a554adcccf40824d83be56cd3ef08245c550ceff53363dfa7ad4","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"be4b8f4a7a9f0c0d345243f4b9bf51a5c0d72350c7602ae1dc2e9d5a44ed4ee3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"7b9d59fb1ee9efd13e2347d20b76c508bfe5992e0e4d4ccb837be763de1843db","src/cdsl/cpu_modes.rs":"b42421b48f77804c2cfae744dc9e3c98c3787746c2649af201e0d4b8997eadae","src/cdsl/encodings.rs":"299dbec5e67907cbb7e8b798913bbc606f26833cb08790d9dae159ba7d8b8c66","src/cdsl/formats.rs":"5ed0d689b791d928e51f9608cb139dde7be810ff1dc4e03c58a6fe79e43eeffd","src/cdsl/instructions.rs":"42b55c2c07878df6c23ba9b1bff78a47c933e9652252421aefd564d8c1f171f0","src/cdsl/isa.rs":"ccabd6848b69eb069c10db61c7e7f86080777495714bb53d03e663c40541be94","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"3e70d11c04a123c9d91075e14af6909a885f37a0c2f86df6aca1b337e2994763","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"4ba2099e2c5df4f603f0a51a4ac19761a4723009cbc0ae66a3e9b82f5c851c05","src/cdsl/types.rs":"9f8221b5d3987b30943ba5f168190cb220b59350e9463ca264ecfd663dbbc3a2","src/cdsl/typevar.rs":"e375a0719b918ef1922296e71758ba1ddc236b9378635db0de980ea36d427049","src/cdsl/xform.rs":"4d4769d47580e25f57ac119a2193a5e33b946545c7e75b0642d255e9cf81575f","src/constant_hash.rs":"91db790f44df312a7478271056db6edf9d12389ee9c675e2d1bb1b60c98353c9","src/default_map.rs":"5e1aeff22953d78083f5184a62da53c92e8b908f5edea30353c048e5201af9e3","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"dd850f3a34a80ece53bd8a40017e77c425c0d0ad044a4efd2c1ee02c71cb614f","src/gen_encodings.rs":"bb598d4eeb8e7365a023ebbb4cc0d8c9f57163b4d0d489047f0fcdbe83880adb","src/gen_inst.rs":"d2c157a9986f31515abd2f154d7d7d8ca61efc5a932bd7ae845af959b1fc1e66","src/gen_legalizer.rs":"9634204a42273d77f0a062bbb04b83e09b11452690af9cddb0faac990fa3b346","src/gen_registers.rs":"bcc1df255045b79d0772d2a1fc9aaac44764ed23ed7acf88f57050aca735dce2","src/gen_settings.rs":"4b34cdd93a52053e88cea7f00b8078518d69fec2e89da054c1d824a8144b666a","src/gen_types.rs":"f6c090e1646a43bf2fe81ae0a7029cc6f7dc6d43285368f56d86c35a21c469a6","src/isa/arm32/mod.rs":"5ca444f18d438f879edb857c75e129931067794a669b607350c4ed648fd92520","src/isa/arm64/mod.rs":"9a1acc8533a1c9be332c565f399cf1c9b5a0a85290bf7bcb82b778fc412d5fa5","src/isa/mod.rs":"a728d5063d34a4ac572ad63ff0f458da33703c58cdd901a0c36276f426fbb0d1","src/isa/riscv/encodings.rs":"cad44ff58cd7626d039824107b3d2d5e8d909e59a25e34c8b5c90ccad76a1c28","src/isa/riscv/mod.rs":"4945ad95284ac157593935722b75f120b4a0e22b133e69a1e9784e6cd3615c0a","src/isa/riscv/recipes.rs":"5cfdc71a3d5640de6ec956eb8eb6a3a85135daa1d6e30d1d6a693b6ad2d12e0e","src/isa/x86/encodings.rs":"e03d12d7ae5aadedc2ea5f0f7952a74b093adc2c747dd0b07be9202955d0ac47","src/isa/x86/instructions.rs":"c438579d98562e6efb67edf5983ffab26a3c7c2d8b20dccbd2667687031fa7f4","src/isa/x86/legalize.rs":"150cf83b605cf0bfc7618937c60d69dbc9504c6c4242806deeb87591b18f6793","src/isa/x86/mod.rs":"1d13c0a294ce85f09d60a2d33d24848733c6053b8d47298b7b0eefbc9b7ee317","src/isa/x86/opcodes.rs":"6558e45e8027b46b2201e0152affc7093a8b10d3e45ef2f457de37af3cc180a0","src/isa/x86/recipes.rs":"43744f2d242ff233e6bf4ed8e13b5c7b024bb0c4735ddd0f6012919f91ab0e85","src/isa/x86/registers.rs":"3cde7d3275971d651ae0f25c88bfb81128b7a35183a969aed81776d4c5141e0e","src/isa/x86/settings.rs":"4e84ff135d6f21595bbd8f56d2e561abd3c123566f2332ac93bb4a9c627f0c00","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"d3dc9d6cb5ba30b1bbdcbfa4505e4897618064dab0b99006fd247d0c93f0b3dc","src/shared/formats.rs":"2757a729ec9b38853b4810cacbd980f44fe8b200184f45b728eb98060578d1fc","src/shared/immediates.rs":"f13c09d14d148d03ab2c6dcfdcd96d5833d0842c49ea437cbf42a085f7cdb45f","src/shared/instructions.rs":"9128d67b0b9c0a86ccc278e637ec5484ce4e5a680f410ae9b0797598bcd42b8f","src/shared/legalize.rs":"e19c1b808b4c2930323b8de2b63fb478c470014d089cf1c4ad8b349c69259979","src/shared/mod.rs":"7b4de39ea3075ba8d1733319c03f1a19d903215b7bb55f877d0f8826f4b43c85","src/shared/settings.rs":"b141f6e6f0baa516ac5bfb919bc51c577353cd7b47ca796677e32eff2bdf16ce","src/shared/types.rs":"b47799d381f3a554adcccf40824d83be56cd3ef08245c550ceff53363dfa7ad4","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen-meta/Cargo.toml
+++ b/third_party/rust/cranelift-codegen-meta/Cargo.toml
@@ -1,20 +1,21 @@
 [package]
 name = "cranelift-codegen-meta"
 authors = ["The Cranelift Project Developers"]
-version = "0.42.0"
+version = "0.44.0"
 description = "Metaprogram for cranelift-codegen code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/CraneStation/cranelift"
 readme = "README.md"
 edition = "2018"
 
 [dependencies]
-cranelift-entity = { path = "../../cranelift-entity", version = "0.42.0", default-features = false }
+cranelift-codegen-shared = { path = "../shared", version = "0.44.0" }
+cranelift-entity = { path = "../../cranelift-entity", version = "0.44.0", default-features = false }
 
 [badges]
 maintenance = { status = "experimental" }
 travis-ci = { repository = "CraneStation/cranelift" }
 
 [features]
 default = ["std"]
 std = ["cranelift-entity/std"]
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/ast.rs
@@ -1,20 +1,20 @@
 use crate::cdsl::formats::FormatRegistry;
 use crate::cdsl::instructions::{InstSpec, Instruction, InstructionPredicate};
 use crate::cdsl::operands::{OperandKind, OperandKindFields};
 use crate::cdsl::types::ValueType;
 use crate::cdsl::typevar::{TypeSetBuilder, TypeVar};
 
-use cranelift_entity::{entity_impl, PrimaryMap};
+use cranelift_entity::{entity_impl, PrimaryMap, SparseMap, SparseMapValue};
 
 use std::fmt;
+use std::iter::IntoIterator;
 
-#[derive(Debug)]
-pub enum Expr {
+pub(crate) enum Expr {
     Var(VarIndex),
     Literal(Literal),
 }
 
 impl Expr {
     pub fn maybe_literal(&self) -> Option<&Literal> {
         match &self {
             Expr::Literal(lit) => Some(lit),
@@ -39,17 +39,17 @@ impl Expr {
         match self {
             Expr::Var(var_index) => var_pool.get(*var_index).to_rust_code(),
             Expr::Literal(literal) => literal.to_rust_code(),
         }
     }
 }
 
 /// An AST definition associates a set of variables with the values produced by an expression.
-pub struct Def {
+pub(crate) struct Def {
     pub apply: Apply,
     pub defined_vars: Vec<VarIndex>,
 }
 
 impl Def {
     pub fn to_comment_string(&self, var_pool: &VarPool) -> String {
         let results = self
             .defined_vars
@@ -62,136 +62,165 @@ impl Def {
         } else {
             format!("({})", results.join(", "))
         };
 
         format!("{} << {}", results, self.apply.to_comment_string(var_pool))
     }
 }
 
-pub struct DefPool {
+pub(crate) struct DefPool {
     pool: PrimaryMap<DefIndex, Def>,
 }
 
 impl DefPool {
     pub fn new() -> Self {
         Self {
             pool: PrimaryMap::new(),
         }
     }
     pub fn get(&self, index: DefIndex) -> &Def {
         self.pool.get(index).unwrap()
     }
     pub fn next_index(&self) -> DefIndex {
         self.pool.next_key()
     }
-    pub fn create(&mut self, apply: Apply, defined_vars: Vec<VarIndex>) -> DefIndex {
+    pub fn create_inst(&mut self, apply: Apply, defined_vars: Vec<VarIndex>) -> DefIndex {
         self.pool.push(Def {
             apply,
             defined_vars,
         })
     }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct DefIndex(u32);
+pub(crate) struct DefIndex(u32);
 entity_impl!(DefIndex);
 
-#[derive(Debug, Clone)]
-enum LiteralValue {
+/// A definition which would lead to generate a block creation.
+#[derive(Clone)]
+pub(crate) struct Block {
+    /// Instruction index after which the block entry is set.
+    pub location: DefIndex,
+    /// Variable holding the new created block.
+    pub name: VarIndex,
+}
+
+pub(crate) struct BlockPool {
+    pool: SparseMap<DefIndex, Block>,
+}
+
+impl SparseMapValue<DefIndex> for Block {
+    fn key(&self) -> DefIndex {
+        self.location
+    }
+}
+
+impl BlockPool {
+    pub fn new() -> Self {
+        Self {
+            pool: SparseMap::new(),
+        }
+    }
+    pub fn get(&self, index: DefIndex) -> Option<&Block> {
+        self.pool.get(index)
+    }
+    pub fn create_block(&mut self, name: VarIndex, location: DefIndex) {
+        if self.pool.contains_key(location) {
+            panic!("Attempt to insert 2 blocks after the same instruction")
+        }
+        self.pool.insert(Block { location, name });
+    }
+    pub fn is_empty(&self) -> bool {
+        self.pool.is_empty()
+    }
+}
+
+// Implement IntoIterator such that we can iterate over blocks which are in the block pool.
+impl<'a> IntoIterator for &'a BlockPool {
+    type Item = <&'a SparseMap<DefIndex, Block> as IntoIterator>::Item;
+    type IntoIter = <&'a SparseMap<DefIndex, Block> as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.pool.into_iter()
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum Literal {
     /// A value of an enumerated immediate operand.
     ///
     /// Some immediate operand kinds like `intcc` and `floatcc` have an enumerated range of values
     /// corresponding to a Rust enum type. An `Enumerator` object is an AST leaf node representing one
     /// of the values.
-    Enumerator(&'static str),
+    Enumerator {
+        rust_type: String,
+        value: &'static str,
+    },
 
     /// A bitwise value of an immediate operand, used for bitwise exact floating point constants.
-    Bits(u64),
+    Bits { rust_type: String, value: u64 },
 
     /// A value of an integer immediate operand.
     Int(i64),
-}
 
-#[derive(Clone)]
-pub struct Literal {
-    kind: OperandKind,
-    value: LiteralValue,
-}
-
-impl fmt::Debug for Literal {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        write!(
-            fmt,
-            "Literal(kind={}, value={:?})",
-            self.kind.name, self.value
-        )
-    }
+    /// A empty list of variable set of arguments.
+    EmptyVarArgs,
 }
 
 impl Literal {
     pub fn enumerator_for(kind: &OperandKind, value: &'static str) -> Self {
-        if let OperandKindFields::ImmEnum(values) = &kind.fields {
-            assert!(
-                values.get(value).is_some(),
-                format!(
-                    "nonexistent value '{}' in enumeration '{}'",
-                    value, kind.name
-                )
-            );
-        } else {
-            panic!("enumerator is for enum values");
-        }
-        Self {
-            kind: kind.clone(),
-            value: LiteralValue::Enumerator(value),
+        let value = match &kind.fields {
+            OperandKindFields::ImmEnum(values) => values.get(value).expect(&format!(
+                "nonexistent value '{}' in enumeration '{}'",
+                value, kind.name
+            )),
+            _ => panic!("enumerator is for enum values"),
+        };
+        Literal::Enumerator {
+            rust_type: kind.rust_type.clone(),
+            value,
         }
     }
 
     pub fn bits(kind: &OperandKind, bits: u64) -> Self {
         match kind.fields {
             OperandKindFields::ImmValue => {}
             _ => panic!("bits_of is for immediate scalar types"),
         }
-        Self {
-            kind: kind.clone(),
-            value: LiteralValue::Bits(bits),
+        Literal::Bits {
+            rust_type: kind.rust_type.clone(),
+            value: bits,
         }
     }
 
     pub fn constant(kind: &OperandKind, value: i64) -> Self {
         match kind.fields {
             OperandKindFields::ImmValue => {}
-            _ => panic!("bits_of is for immediate scalar types"),
+            _ => panic!("constant is for immediate scalar types"),
         }
-        Self {
-            kind: kind.clone(),
-            value: LiteralValue::Int(value),
-        }
+        Literal::Int(value)
+    }
+
+    pub fn empty_vararg() -> Self {
+        Literal::EmptyVarArgs
     }
 
     pub fn to_rust_code(&self) -> String {
-        let maybe_values = match &self.kind.fields {
-            OperandKindFields::ImmEnum(values) => Some(values),
-            OperandKindFields::ImmValue => None,
-            _ => panic!("impossible per construction"),
-        };
-
-        match self.value {
-            LiteralValue::Enumerator(value) => {
-                format!("{}::{}", self.kind.rust_type, maybe_values.unwrap()[value])
-            }
-            LiteralValue::Bits(bits) => format!("{}::with_bits({:#x})", self.kind.rust_type, bits),
-            LiteralValue::Int(val) => val.to_string(),
+        match self {
+            Literal::Enumerator { rust_type, value } => format!("{}::{}", rust_type, value),
+            Literal::Bits { rust_type, value } => format!("{}::with_bits({:#x})", rust_type, value),
+            Literal::Int(val) => val.to_string(),
+            Literal::EmptyVarArgs => "&[]".into(),
         }
     }
 }
 
 #[derive(Clone, Copy, Debug)]
-pub enum PatternPosition {
+pub(crate) enum PatternPosition {
     Source,
     Destination,
 }
 
 /// A free variable.
 ///
 /// When variables are used in `XForms` with source and destination patterns, they are classified
 /// as follows:
@@ -203,17 +232,17 @@ pub enum PatternPosition {
 /// values may have uses outside the source pattern, and the destination pattern must compute the
 /// same value.
 ///
 /// Intermediate values: Values that are defined in the source pattern, but not in the destination
 /// pattern. These may have uses outside the source pattern, so the defining instruction can't be
 /// deleted immediately.
 ///
 /// Temporary values are defined only in the destination pattern.
-pub struct Var {
+pub(crate) struct Var {
     pub name: &'static str,
 
     /// The `Def` defining this variable in a source pattern.
     pub src_def: Option<DefIndex>,
 
     /// The `Def` defining this variable in a destination pattern.
     pub dst_def: Option<DefIndex>,
 
@@ -331,20 +360,20 @@ impl fmt::Debug for Var {
             self.name,
             if self.src_def.is_some() { ", src" } else { "" },
             if self.dst_def.is_some() { ", dst" } else { "" }
         ))
     }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct VarIndex(u32);
+pub(crate) struct VarIndex(u32);
 entity_impl!(VarIndex);
 
-pub struct VarPool {
+pub(crate) struct VarPool {
     pool: PrimaryMap<VarIndex, Var>,
 }
 
 impl VarPool {
     pub fn new() -> Self {
         Self {
             pool: PrimaryMap::new(),
         }
@@ -359,18 +388,17 @@ impl VarPool {
         self.pool.push(Var::new(name))
     }
 }
 
 /// Apply an instruction to arguments.
 ///
 /// An `Apply` AST expression is created by using function call syntax on instructions. This
 /// applies to both bound and unbound polymorphic instructions.
-#[derive(Debug)]
-pub struct Apply {
+pub(crate) struct Apply {
     pub inst: Instruction,
     pub args: Vec<Expr>,
     pub value_types: Vec<ValueType>,
 }
 
 impl Apply {
     pub fn new(target: InstSpec, args: Vec<Expr>) -> Self {
         let (inst, value_types) = match target {
@@ -390,23 +418,48 @@ impl Apply {
             format!("incorrect number of arguments in instruction {}", inst.name)
         );
 
         // Check that the kinds of Literals arguments match the expected operand.
         for &imm_index in &inst.imm_opnums {
             let arg = &args[imm_index];
             if let Some(literal) = arg.maybe_literal() {
                 let op = &inst.operands_in[imm_index];
-                assert!(
-                    op.kind.name == literal.kind.name,
-                    format!(
-                        "Passing literal of kind {} to field of wrong kind {}",
-                        literal.kind.name, op.kind.name
-                    )
-                );
+                match &op.kind.fields {
+                    OperandKindFields::ImmEnum(values) => {
+                        if let Literal::Enumerator { value, .. } = literal {
+                            assert!(
+                                values.iter().any(|(_key, v)| v == value),
+                                "Nonexistent enum value '{}' passed to field of kind '{}' -- \
+                                 did you use the right enum?",
+                                value,
+                                op.kind.name
+                            );
+                        } else {
+                            panic!(
+                                "Passed non-enum field value {:?} to field of kind {}",
+                                literal, op.kind.name
+                            );
+                        }
+                    }
+                    OperandKindFields::ImmValue => match &literal {
+                        Literal::Enumerator { value, .. } => panic!(
+                            "Expected immediate value in immediate field of kind '{}', \
+                             obtained enum value '{}'",
+                            op.kind.name, value
+                        ),
+                        Literal::Bits { .. } | Literal::Int(_) | Literal::EmptyVarArgs => {}
+                    },
+                    _ => {
+                        panic!(
+                            "Literal passed to non-literal field of kind {}",
+                            op.kind.name
+                        );
+                    }
+                }
             }
         }
 
         Self {
             inst,
             args,
             value_types,
         }
@@ -506,63 +559,69 @@ impl Apply {
         }
 
         format!("{}({})", self.inst.snake_name(), args)
     }
 }
 
 // Simple helpers for legalize actions construction.
 
-pub enum DummyExpr {
+pub(crate) enum DummyExpr {
     Var(DummyVar),
     Literal(Literal),
     Apply(InstSpec, Vec<DummyExpr>),
+    Block(DummyVar),
 }
 
 #[derive(Clone)]
-pub struct DummyVar {
+pub(crate) struct DummyVar {
     pub name: &'static str,
 }
 
 impl Into<DummyExpr> for DummyVar {
     fn into(self) -> DummyExpr {
         DummyExpr::Var(self)
     }
 }
 impl Into<DummyExpr> for Literal {
     fn into(self) -> DummyExpr {
         DummyExpr::Literal(self)
     }
 }
 
-pub fn var(name: &'static str) -> DummyVar {
+pub(crate) fn var(name: &'static str) -> DummyVar {
     DummyVar { name }
 }
 
-pub struct DummyDef {
+pub(crate) struct DummyDef {
     pub expr: DummyExpr,
     pub defined_vars: Vec<DummyVar>,
 }
 
-pub struct ExprBuilder {
+pub(crate) struct ExprBuilder {
     expr: DummyExpr,
 }
 
 impl ExprBuilder {
     pub fn apply(inst: InstSpec, args: Vec<DummyExpr>) -> Self {
         let expr = DummyExpr::Apply(inst, args);
         Self { expr }
     }
 
     pub fn assign_to(self, defined_vars: Vec<DummyVar>) -> DummyDef {
         DummyDef {
             expr: self.expr,
             defined_vars,
         }
     }
+
+    pub fn block(name: DummyVar) -> Self {
+        let expr = DummyExpr::Block(name);
+        Self { expr }
+    }
 }
 
 macro_rules! def_rhs {
     // inst(a, b, c)
     ($inst:ident($($src:expr),*)) => {
         ExprBuilder::apply($inst.into(), vec![$($src.clone().into()),*])
     };
 
@@ -584,8 +643,16 @@ macro_rules! def {
         def_rhs!($($tt)*).assign_to(vec![$($dest.clone()),*])
     };
 
     // An instruction with no results.
     ($($tt:tt)*) => {
         def_rhs!($($tt)*).assign_to(Vec::new())
     }
 }
+
+// Helper macro to define legalization recipes.
+macro_rules! ebb {
+    // An basic block definition, splitting the current block in 2.
+    ($block: ident) => {
+        ExprBuilder::block($block).assign_to(Vec::new())
+    };
+}
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/cpu_modes.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/cpu_modes.rs
@@ -1,16 +1,16 @@
 use std::collections::{hash_map, HashMap, HashSet};
 use std::iter::FromIterator;
 
 use crate::cdsl::encodings::Encoding;
 use crate::cdsl::types::{LaneType, ValueType};
 use crate::cdsl::xform::{TransformGroup, TransformGroupIndex};
 
-pub struct CpuMode {
+pub(crate) struct CpuMode {
     pub name: &'static str,
     default_legalize: Option<TransformGroupIndex>,
     monomorphic_legalize: Option<TransformGroupIndex>,
     typed_legalize: HashMap<ValueType, TransformGroupIndex>,
     pub encodings: Vec<Encoding>,
 }
 
 impl CpuMode {
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/encodings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/encodings.rs
@@ -15,17 +15,17 @@ use crate::cdsl::types::ValueType;
 ///
 /// The concrete instruction can be in three different forms:
 ///
 /// 1. A naked opcode: `trap` for non-polymorphic instructions.
 /// 2. With bound type variables: `iadd.i32` for polymorphic instructions.
 /// 3. With operands providing constraints: `icmp.i32(intcc.eq, x, y)`.
 ///
 /// If the instruction is polymorphic, all type variables must be provided.
-pub struct EncodingContent {
+pub(crate) struct EncodingContent {
     /// The `Instruction` or `BoundInstruction` being encoded.
     inst: InstSpec,
 
     /// The `EncodingRecipe` to use.
     pub recipe: EncodingRecipeNumber,
 
     /// Additional encoding bits to be interpreted by `recipe`.
     pub encbits: u16,
@@ -44,19 +44,19 @@ impl EncodingContent {
     pub fn inst(&self) -> &Instruction {
         self.inst.inst()
     }
     pub fn to_rust_comment(&self, recipes: &Recipes) -> String {
         format!("[{}#{:02x}]", recipes[self.recipe].name, self.encbits)
     }
 }
 
-pub type Encoding = Rc<EncodingContent>;
+pub(crate) type Encoding = Rc<EncodingContent>;
 
-pub struct EncodingBuilder {
+pub(crate) struct EncodingBuilder {
     inst: InstSpec,
     recipe: EncodingRecipeNumber,
     encbits: u16,
     inst_predicate: Option<InstructionPredicate>,
     isa_predicate: Option<SettingPredicateNumber>,
     bound_type: Option<ValueType>,
 }
 
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/instructions.rs
@@ -8,16 +8,17 @@ use std::rc::Rc;
 use crate::cdsl::camel_case;
 use crate::cdsl::formats::{
     FormatField, FormatRegistry, InstructionFormat, InstructionFormatIndex,
 };
 use crate::cdsl::operands::Operand;
 use crate::cdsl::type_inference::Constraint;
 use crate::cdsl::types::{LaneType, ReferenceType, ValueType, VectorType};
 use crate::cdsl::typevar::TypeVar;
+use cranelift_codegen_shared::condcodes::IntCC;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct OpcodeNumber(u32);
 entity_impl!(OpcodeNumber);
 
 pub type AllInstructions = PrimaryMap<OpcodeNumber, Instruction>;
 
 pub struct InstructionGroupBuilder<'format_reg, 'all_inst> {
@@ -609,24 +610,33 @@ pub enum FormatPredicateKind {
     /// Is the immediate format field member an integer equal to zero?
     IsZeroInt,
     /// Is the immediate format field member equal to zero? (float32 version)
     IsZero32BitFloat,
 
     /// Is the immediate format field member equal to zero? (float64 version)
     IsZero64BitFloat,
 
+    /// Is the immediate format field member equal zero in all lanes?
+    IsAllZeroes128Bit,
+
+    /// Does the immediate format field member have ones in all bits of all lanes?
+    IsAllOnes128Bit,
+
     /// Has the value list (in member_name) the size specified in parameter?
     LengthEquals(usize),
 
     /// Is the referenced function colocated?
     IsColocatedFunc,
 
     /// Is the referenced data object colocated?
     IsColocatedData,
+
+    /// Does the operation have a specific condition code?
+    HasConditionCode(IntCC),
 }
 
 #[derive(Clone, Hash, PartialEq, Eq)]
 pub struct FormatPredicateNode {
     format_name: &'static str,
     member_name: &'static str,
     kind: FormatPredicateKind,
 }
@@ -685,26 +695,38 @@ impl FormatPredicateNode {
                 format!("predicates::is_zero_int({})", self.member_name)
             }
             FormatPredicateKind::IsZero32BitFloat => {
                 format!("predicates::is_zero_32_bit_float({})", self.member_name)
             }
             FormatPredicateKind::IsZero64BitFloat => {
                 format!("predicates::is_zero_64_bit_float({})", self.member_name)
             }
+            FormatPredicateKind::IsAllZeroes128Bit => format!(
+                "predicates::is_all_zeroes_128_bit(func.dfg.constants.get({}))",
+                self.member_name
+            ),
+            FormatPredicateKind::IsAllOnes128Bit => format!(
+                "predicates::is_all_ones_128_bit(func.dfg.constants.get({}))",
+                self.member_name
+            ),
             FormatPredicateKind::LengthEquals(num) => format!(
                 "predicates::has_length_of({}, {}, func)",
                 self.member_name, num
             ),
             FormatPredicateKind::IsColocatedFunc => {
                 format!("predicates::is_colocated_func({}, func)", self.member_name,)
             }
             FormatPredicateKind::IsColocatedData => {
                 format!("predicates::is_colocated_data({}, func)", self.member_name)
             }
+            FormatPredicateKind::HasConditionCode(code) => format!(
+                "predicates::is_equal({}, IntCC::{:?})",
+                self.member_name, code
+            ),
         }
     }
 }
 
 #[derive(Clone, Hash, PartialEq, Eq)]
 pub enum TypePredicateNode {
     /// Is the value argument (at the index designated by the first member) the same type as the
     /// type name (second member)?
@@ -924,16 +946,38 @@ impl InstructionPredicate {
     ) -> InstructionPredicateNode {
         InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
             format,
             field_name,
             FormatPredicateKind::IsZero64BitFloat,
         ))
     }
 
+    pub fn new_is_all_zeroes_128bit(
+        format: &InstructionFormat,
+        field_name: &'static str,
+    ) -> InstructionPredicateNode {
+        InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
+            format,
+            field_name,
+            FormatPredicateKind::IsAllZeroes128Bit,
+        ))
+    }
+
+    pub fn new_is_all_ones_128bit(
+        format: &InstructionFormat,
+        field_name: &'static str,
+    ) -> InstructionPredicateNode {
+        InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
+            format,
+            field_name,
+            FormatPredicateKind::IsAllOnes128Bit,
+        ))
+    }
+
     pub fn new_length_equals(format: &InstructionFormat, size: usize) -> InstructionPredicateNode {
         assert!(
             format.has_value_list,
             "the format must be variadic in number of arguments"
         );
         InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new_raw(
             format,
             "args",
@@ -956,16 +1000,28 @@ impl InstructionPredicate {
         let format = format_registry.get(format_registry.by_name("UnaryGlobalValue"));
         InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
             format,
             "global_value",
             FormatPredicateKind::IsColocatedData,
         ))
     }
 
+    pub fn new_has_condition_code(
+        format: &InstructionFormat,
+        condition_code: IntCC,
+        field_name: &'static str,
+    ) -> InstructionPredicateNode {
+        InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
+            format,
+            field_name,
+            FormatPredicateKind::HasConditionCode(condition_code),
+        ))
+    }
+
     pub fn and(mut self, new_node: InstructionPredicateNode) -> Self {
         let node = self.node;
         let mut and_nodes = match node {
             Some(node) => match node {
                 InstructionPredicateNode::And(nodes) => nodes,
                 InstructionPredicateNode::Or(_) => {
                     panic!("Can't mix and/or without implementing operator precedence!")
                 }
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs
@@ -3,17 +3,17 @@ use std::iter::FromIterator;
 
 use crate::cdsl::cpu_modes::CpuMode;
 use crate::cdsl::instructions::{InstructionGroup, InstructionPredicateMap};
 use crate::cdsl::recipes::Recipes;
 use crate::cdsl::regs::IsaRegs;
 use crate::cdsl::settings::SettingGroup;
 use crate::cdsl::xform::{TransformGroupIndex, TransformGroups};
 
-pub struct TargetIsa {
+pub(crate) struct TargetIsa {
     pub name: &'static str,
     pub instructions: InstructionGroup,
     pub settings: SettingGroup,
     pub regs: IsaRegs,
     pub recipes: Recipes,
     pub cpu_modes: Vec<CpuMode>,
     pub encodings_predicates: InstructionPredicateMap,
 
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/type_inference.rs
@@ -117,17 +117,17 @@ enum TypeEnvRank {
     Input = 4,
     Intermediate = 3,
     Output = 2,
     Temp = 1,
     Internal = 0,
 }
 
 /// Class encapsulating the necessary bookkeeping for type inference.
-pub struct TypeEnvironment {
+pub(crate) struct TypeEnvironment {
     vars: HashSet<VarIndex>,
     ranks: HashMap<TypeVar, TypeEnvRank>,
     equivalency_map: HashMap<TypeVar, TypeVar>,
     pub constraints: Vec<Constraint>,
 }
 
 impl TypeEnvironment {
     fn new() -> Self {
@@ -597,17 +597,17 @@ fn infer_definition(
     for constraint in &inst.constraints {
         type_env.add_constraint(constraint.translate_with_map(&original_to_own_typevar));
     }
 
     Ok(type_env)
 }
 
 /// Perform type inference on an transformation. Return an updated type environment or error.
-pub fn infer_transform(
+pub(crate) fn infer_transform(
     src: DefIndex,
     dst: &Vec<DefIndex>,
     def_pool: &DefPool,
     var_pool: &mut VarPool,
 ) -> Result<TypeEnvironment, String> {
     let mut type_env = TypeEnvironment::new();
     let mut last_type_index = 0;
 
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/typevar.rs
@@ -846,17 +846,17 @@ impl TypeSetBuilder {
     pub fn specials(mut self, specials: Vec<SpecialType>) -> Self {
         assert!(self.specials.is_empty());
         self.specials = specials;
         self
     }
 
     pub fn build(self) -> TypeSet {
         let min_lanes = if self.includes_scalars { 1 } else { 2 };
-;
+
         let bools = range_to_set(self.bools.to_range(1..MAX_BITS, None))
             .into_iter()
             .filter(legal_bool)
             .collect();
 
         TypeSet::new(
             range_to_set(self.simd_lanes.to_range(min_lanes..MAX_LANES, Some(1))),
             range_to_set(self.ints.to_range(8..MAX_BITS, None)),
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/xform.rs
@@ -1,10 +1,11 @@
 use crate::cdsl::ast::{
-    Apply, DefIndex, DefPool, DummyDef, DummyExpr, Expr, PatternPosition, VarIndex, VarPool,
+    Apply, BlockPool, DefIndex, DefPool, DummyDef, DummyExpr, Expr, PatternPosition, VarIndex,
+    VarPool,
 };
 use crate::cdsl::instructions::Instruction;
 use crate::cdsl::type_inference::{infer_transform, TypeEnvironment};
 use crate::cdsl::typevar::TypeVar;
 
 use cranelift_entity::{entity_impl, PrimaryMap};
 
 use std::collections::{HashMap, HashSet};
@@ -12,58 +13,62 @@ use std::iter::FromIterator;
 
 /// An instruction transformation consists of a source and destination pattern.
 ///
 /// Patterns are expressed in *register transfer language* as tuples of Def or Expr nodes. A
 /// pattern may optionally have a sequence of TypeConstraints, that additionally limit the set of
 /// cases when it applies.
 ///
 /// The source pattern can contain only a single instruction.
-pub struct Transform {
+pub(crate) struct Transform {
     pub src: DefIndex,
     pub dst: Vec<DefIndex>,
     pub var_pool: VarPool,
     pub def_pool: DefPool,
+    pub block_pool: BlockPool,
     pub type_env: TypeEnvironment,
 }
 
 type SymbolTable = HashMap<&'static str, VarIndex>;
 
 impl Transform {
     fn new(src: DummyDef, dst: Vec<DummyDef>) -> Self {
         let mut var_pool = VarPool::new();
         let mut def_pool = DefPool::new();
+        let mut block_pool = BlockPool::new();
 
         let mut input_vars: Vec<VarIndex> = Vec::new();
         let mut defined_vars: Vec<VarIndex> = Vec::new();
 
         // Maps variable names to our own Var copies.
         let mut symbol_table: SymbolTable = SymbolTable::new();
 
         // Rewrite variables in src and dst using our own copies.
         let src = rewrite_def_list(
             PatternPosition::Source,
             vec![src],
             &mut symbol_table,
             &mut input_vars,
             &mut defined_vars,
             &mut var_pool,
             &mut def_pool,
+            &mut block_pool,
         )[0];
 
         let num_src_inputs = input_vars.len();
 
         let dst = rewrite_def_list(
             PatternPosition::Destination,
             dst,
             &mut symbol_table,
             &mut input_vars,
             &mut defined_vars,
             &mut var_pool,
             &mut def_pool,
+            &mut block_pool,
         );
 
         // Sanity checks.
         for &var_index in &input_vars {
             assert!(
                 var_pool.get(var_index).is_input(),
                 format!("'{:?}' used as both input and def", var_pool.get(var_index))
             );
@@ -117,53 +122,66 @@ impl Transform {
             var.set_typevar(canon_tv);
         }
 
         Self {
             src,
             dst,
             var_pool,
             def_pool,
+            block_pool,
             type_env,
         }
     }
 
     fn verify_legalize(&self) {
         let def = self.def_pool.get(self.src);
         for &var_index in def.defined_vars.iter() {
             let defined_var = self.var_pool.get(var_index);
             assert!(
                 defined_var.is_output(),
                 format!("{:?} not defined in the destination pattern", defined_var)
             );
         }
     }
 }
 
+/// Inserts, if not present, a name in the `symbol_table`. Then returns its index in the variable
+/// pool `var_pool`. If the variable was not present in the symbol table, then add it to the list of
+/// `defined_vars`.
+fn var_index(
+    name: &'static str,
+    symbol_table: &mut SymbolTable,
+    defined_vars: &mut Vec<VarIndex>,
+    var_pool: &mut VarPool,
+) -> VarIndex {
+    match symbol_table.get(name) {
+        Some(&existing_var) => existing_var,
+        None => {
+            // Materialize the variable.
+            let new_var = var_pool.create(name);
+            symbol_table.insert(name, new_var);
+            defined_vars.push(new_var);
+            new_var
+        }
+    }
+}
+
 /// Given a list of symbols defined in a Def, rewrite them to local symbols. Yield the new locals.
 fn rewrite_defined_vars(
     position: PatternPosition,
     dummy_def: &DummyDef,
     def_index: DefIndex,
     symbol_table: &mut SymbolTable,
     defined_vars: &mut Vec<VarIndex>,
     var_pool: &mut VarPool,
 ) -> Vec<VarIndex> {
     let mut new_defined_vars = Vec::new();
     for var in &dummy_def.defined_vars {
-        let own_var = match symbol_table.get(var.name) {
-            Some(&existing_var) => existing_var,
-            None => {
-                // Materialize the variable.
-                let new_var = var_pool.create(var.name);
-                symbol_table.insert(var.name, new_var);
-                defined_vars.push(new_var);
-                new_var
-            }
-        };
+        let own_var = var_index(var.name, symbol_table, defined_vars, var_pool);
         var_pool.get_mut(own_var).set_def(position, def_index);
         new_defined_vars.push(own_var);
     }
     new_defined_vars
 }
 
 /// Find all uses of variables in `expr` and replace them with our own local symbols.
 fn rewrite_expr(
@@ -192,88 +210,105 @@ fn rewrite_expr(
             .map(|operand| format!("{}: {}", operand.name, operand.kind.name))
             .collect::<Vec<_>>(),
     );
 
     let mut args = Vec::new();
     for (i, arg) in dummy_args.into_iter().enumerate() {
         match arg {
             DummyExpr::Var(var) => {
-                let own_var = match symbol_table.get(var.name) {
-                    Some(&own_var) => {
-                        let var = var_pool.get(own_var);
-                        assert!(
-                            var.is_input() || var.get_def(position).is_some(),
-                            format!("{:?} used as both input and def", var)
-                        );
-                        own_var
-                    }
-                    None => {
-                        // First time we're using this variable.
-                        let own_var = var_pool.create(var.name);
-                        symbol_table.insert(var.name, own_var);
-                        input_vars.push(own_var);
-                        own_var
-                    }
-                };
+                let own_var = var_index(var.name, symbol_table, input_vars, var_pool);
+                let var = var_pool.get(own_var);
+                assert!(
+                    var.is_input() || var.get_def(position).is_some(),
+                    format!("{:?} used as both input and def", var)
+                );
                 args.push(Expr::Var(own_var));
             }
             DummyExpr::Literal(literal) => {
                 assert!(!apply_target.inst().operands_in[i].is_value());
                 args.push(Expr::Literal(literal));
             }
             DummyExpr::Apply(..) => {
                 panic!("Recursive apply is not allowed.");
             }
+            DummyExpr::Block(_block) => {
+                panic!("Blocks are not valid arguments.");
+            }
         }
     }
 
     Apply::new(apply_target, args)
 }
 
 fn rewrite_def_list(
     position: PatternPosition,
     dummy_defs: Vec<DummyDef>,
     symbol_table: &mut SymbolTable,
     input_vars: &mut Vec<VarIndex>,
     defined_vars: &mut Vec<VarIndex>,
     var_pool: &mut VarPool,
     def_pool: &mut DefPool,
+    block_pool: &mut BlockPool,
 ) -> Vec<DefIndex> {
     let mut new_defs = Vec::new();
+    // Register variable names of new blocks first as a block name can be used to jump forward. Thus
+    // the name has to be registered first to avoid misinterpreting it as an input-var.
+    for dummy_def in dummy_defs.iter() {
+        if let DummyExpr::Block(ref var) = dummy_def.expr {
+            var_index(var.name, symbol_table, defined_vars, var_pool);
+        }
+    }
+
+    // Iterate over the definitions and blocks, to map variables names to inputs or outputs.
     for dummy_def in dummy_defs {
         let def_index = def_pool.next_index();
 
         let new_defined_vars = rewrite_defined_vars(
             position,
             &dummy_def,
             def_index,
             symbol_table,
             defined_vars,
             var_pool,
         );
-        let new_apply = rewrite_expr(position, dummy_def.expr, symbol_table, input_vars, var_pool);
+        if let DummyExpr::Block(var) = dummy_def.expr {
+            let var_index = *symbol_table
+                .get(var.name)
+                .or_else(|| {
+                    panic!(
+                        "Block {} was not registered during the first visit",
+                        var.name
+                    )
+                })
+                .unwrap();
+            var_pool.get_mut(var_index).set_def(position, def_index);
+            block_pool.create_block(var_index, def_index);
+        } else {
+            let new_apply =
+                rewrite_expr(position, dummy_def.expr, symbol_table, input_vars, var_pool);
 
-        assert!(
-            def_pool.next_index() == def_index,
-            "shouldn't have created new defs in the meanwhile"
-        );
-        assert_eq!(
-            new_apply.inst.value_results.len(),
-            new_defined_vars.len(),
-            "number of Var results in instruction is incorrect"
-        );
+            assert!(
+                def_pool.next_index() == def_index,
+                "shouldn't have created new defs in the meanwhile"
+            );
+            assert_eq!(
+                new_apply.inst.value_results.len(),
+                new_defined_vars.len(),
+                "number of Var results in instruction is incorrect"
+            );
 
-        new_defs.push(def_pool.create(new_apply, new_defined_vars));
+            new_defs.push(def_pool.create_inst(new_apply, new_defined_vars));
+        }
     }
     new_defs
 }
 
 /// A group of related transformations.
-pub struct TransformGroup {
+pub(crate) struct TransformGroup {
     pub name: &'static str,
     pub doc: &'static str,
     pub chain_with: Option<TransformGroupIndex>,
     pub isa_name: Option<&'static str>,
     pub id: TransformGroupIndex,
 
     /// Maps Instruction camel_case names to custom legalization functions names.
     pub custom_legalizes: HashMap<String, &'static str>,
@@ -289,20 +324,20 @@ impl TransformGroup {
                 self.name.to_string()
             }
             None => format!("crate::legalizer::{}", self.name),
         }
     }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct TransformGroupIndex(u32);
+pub(crate) struct TransformGroupIndex(u32);
 entity_impl!(TransformGroupIndex);
 
-pub struct TransformGroupBuilder {
+pub(crate) struct TransformGroupBuilder {
     name: &'static str,
     doc: &'static str,
     chain_with: Option<TransformGroupIndex>,
     isa_name: Option<&'static str>,
     pub custom_legalizes: HashMap<String, &'static str>,
     pub transforms: Vec<Transform>,
 }
 
@@ -364,17 +399,17 @@ impl TransformGroupBuilder {
             id: next_id,
             chain_with: self.chain_with,
             custom_legalizes: self.custom_legalizes,
             transforms: self.transforms,
         })
     }
 }
 
-pub struct TransformGroups {
+pub(crate) struct TransformGroups {
     groups: PrimaryMap<TransformGroupIndex, TransformGroup>,
 }
 
 impl TransformGroups {
     pub fn new() -> Self {
         Self {
             groups: PrimaryMap::new(),
         }
--- a/third_party/rust/cranelift-codegen-meta/src/constant_hash.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/constant_hash.rs
@@ -1,22 +1,22 @@
 use std::iter;
 
-pub fn simple_hash(s: &str) -> usize {
+pub(crate) fn simple_hash(s: &str) -> usize {
     let mut h: u32 = 5381;
     for c in s.chars() {
         h = (h ^ c as u32).wrapping_add(h.rotate_right(6));
     }
     h as usize
 }
 
 /// Compute an open addressed, quadratically probed hash table containing
 /// `items`. The returned table is a list containing the elements of the
 /// iterable `items` and `None` in unused slots.
-pub fn generate_table<'cont, T, I: iter::Iterator<Item = &'cont T>, H: Fn(&T) -> usize>(
+pub(crate) fn generate_table<'cont, T, I: iter::Iterator<Item = &'cont T>, H: Fn(&T) -> usize>(
     items: I,
     num_items: usize,
     hash_function: H,
 ) -> Vec<Option<&'cont T>> {
     let size = (1.20 * num_items as f64) as usize;
     // TODO do we really need the multiply by two here?
     let size = if size.is_power_of_two() {
         size * 2
--- a/third_party/rust/cranelift-codegen-meta/src/default_map.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/default_map.rs
@@ -1,12 +1,12 @@
 use std::collections::HashMap;
 use std::hash::Hash;
 
-pub trait MapWithDefault<K, V: Default> {
+pub(crate) trait MapWithDefault<K, V: Default> {
     fn get_or_default(&mut self, k: K) -> &mut V;
 }
 
 impl<K: Eq + Hash, V: Default> MapWithDefault<K, V> for HashMap<K, V> {
     fn get_or_default(&mut self, k: K) -> &mut V {
         self.entry(k).or_insert_with(|| V::default())
     }
 }
--- a/third_party/rust/cranelift-codegen-meta/src/gen_binemit.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_binemit.rs
@@ -206,17 +206,17 @@ fn gen_isa(formats: &FormatRegistry, isa
         fmt.indent(|fmt| {
             fmt.line("bad_encoding(func, inst);");
         });
         fmt.line("}");
     });
     fmt.line("}");
 }
 
-pub fn generate(
+pub(crate) fn generate(
     formats: &FormatRegistry,
     isa_name: &str,
     recipes: &Recipes,
     binemit_filename: &str,
     out_dir: &str,
 ) -> Result<(), error::Error> {
     let mut fmt = Formatter::new();
     gen_isa(formats, isa_name, recipes, &mut fmt);
--- a/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_inst.rs
@@ -92,19 +92,24 @@ fn gen_instruction_data(registry: &Forma
             fmtln!(fmt, "},");
         }
     });
     fmt.line("}");
 }
 
 fn gen_arguments_method(registry: &FormatRegistry, fmt: &mut Formatter, is_mut: bool) {
     let (method, mut_, rslice, as_slice) = if is_mut {
-        ("arguments_mut", "mut ", "ref_slice_mut", "as_mut_slice")
+        (
+            "arguments_mut",
+            "mut ",
+            "core::slice::from_mut",
+            "as_mut_slice",
+        )
     } else {
-        ("arguments", "", "ref_slice", "as_slice")
+        ("arguments", "", "core::slice::from_ref", "as_slice")
     };
 
     fmtln!(
         fmt,
         "pub fn {}<'a>(&'a {}self, pool: &'a {}ir::ValueListPool) -> &{}[Value] {{",
         method,
         mut_,
         mut_,
--- a/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs
@@ -396,42 +396,74 @@ fn gen_transform<'a>(
     // Emit any runtime checks; these will rebind `predicate` emitted by unwrap_inst().
     for constraint in &transform.type_env.constraints {
         emit_runtime_typecheck(constraint, type_sets, fmt);
     }
 
     // Guard the actual expansion by `predicate`.
     fmt.line("if predicate {");
     fmt.indent(|fmt| {
+        // If we are adding some blocks, we need to recall the original block, such that we can
+        // recompute it.
+        if !transform.block_pool.is_empty() {
+            fmt.line("let orig_ebb = pos.current_ebb().unwrap();");
+        }
+
         // If we're going to delete `inst`, we need to detach its results first so they can be
         // reattached during pattern expansion.
         if !replace_inst {
             fmt.line("pos.func.dfg.clear_results(inst);");
         }
 
+        // Emit new block creation.
+        for block in &transform.block_pool {
+            let var = transform.var_pool.get(block.name);
+            fmtln!(fmt, "let {} = pos.func.dfg.make_ebb();", var.name);
+        }
+
         // Emit the destination pattern.
         for &def_index in &transform.dst {
+            if let Some(block) = transform.block_pool.get(def_index) {
+                let var = transform.var_pool.get(block.name);
+                fmtln!(fmt, "pos.insert_ebb({});", var.name);
+            }
             emit_dst_inst(
                 transform.def_pool.get(def_index),
                 &transform.def_pool,
                 &transform.var_pool,
                 fmt,
             );
         }
 
+        // Insert a new block after the last instruction, if needed.
+        let def_next_index = transform.def_pool.next_index();
+        if let Some(block) = transform.block_pool.get(def_next_index) {
+            let var = transform.var_pool.get(block.name);
+            fmtln!(fmt, "pos.insert_ebb({});", var.name);
+        }
+
         // Delete the original instruction if we didn't have an opportunity to replace it.
         if !replace_inst {
             fmt.line("let removed = pos.remove_inst();");
             fmt.line("debug_assert_eq!(removed, inst);");
         }
 
-        if transform.def_pool.get(transform.src).apply.inst.is_branch {
-            // A branch might have been legalized into multiple branches, so we need to recompute
-            // the cfg.
-            fmt.line("cfg.recompute_ebb(pos.func, pos.current_ebb().unwrap());");
+        if transform.block_pool.is_empty() {
+            if transform.def_pool.get(transform.src).apply.inst.is_branch {
+                // A branch might have been legalized into multiple branches, so we need to recompute
+                // the cfg.
+                fmt.line("cfg.recompute_ebb(pos.func, pos.current_ebb().unwrap());");
+            }
+        } else {
+            // Update CFG for the new blocks.
+            fmt.line("cfg.recompute_ebb(pos.func, orig_ebb);");
+            for block in &transform.block_pool {
+                let var = transform.var_pool.get(block.name);
+                fmtln!(fmt, "cfg.recompute_ebb(pos.func, {});", var.name);
+            }
         }
 
         fmt.line("return true;");
     });
     fmt.line("}");
 }
 
 fn gen_transform_group<'a>(
@@ -572,17 +604,17 @@ fn gen_isa(
         for &group_index in direct_groups {
             fmtln!(fmt, "{},", transform_groups.get(group_index).rust_name());
         }
     });
     fmtln!(fmt, "];");
 }
 
 /// Generate the legalizer files.
-pub fn generate(
+pub(crate) fn generate(
     isas: &Vec<TargetIsa>,
     format_registry: &FormatRegistry,
     transform_groups: &TransformGroups,
     filename_prefix: &str,
     out_dir: &str,
 ) -> Result<(), error::Error> {
     let mut shared_group_names = HashSet::new();
 
--- a/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs
@@ -128,14 +128,14 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Fo
         fmt.indent(|fmt| {
             fmtln!(fmt, "self as RegUnit");
         });
         fmtln!(fmt, "}");
     });
     fmtln!(fmt, "}");
 }
 
-pub fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> {
+pub(crate) fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> {
     let mut fmt = Formatter::new();
     gen_isa(&isa, &mut fmt);
     fmt.update_file(filename, out_dir)?;
     Ok(())
 }
--- a/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_settings.rs
@@ -426,17 +426,17 @@ fn gen_group(group: &SettingGroup, paren
     gen_constructor(group, parent, fmt);
     gen_enum_types(group, fmt);
     gen_getters(group, fmt);
     gen_descriptors(group, fmt);
     gen_template(group, fmt);
     gen_display(group, fmt);
 }
 
-pub fn generate(
+pub(crate) fn generate(
     settings: &SettingGroup,
     parent_group: ParentGroup,
     filename: &str,
     out_dir: &str,
 ) -> Result<(), error::Error> {
     let mut fmt = Formatter::new();
     gen_group(&settings, parent_group, &mut fmt);
     fmt.update_file(filename, out_dir)?;
--- a/third_party/rust/cranelift-codegen-meta/src/gen_types.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_types.rs
@@ -63,14 +63,14 @@ fn emit_types(fmt: &mut srcgen::Formatte
     for vec_size in &[64_u64, 128, 256, 512] {
         emit_vectors(*vec_size, fmt)?;
     }
 
     Ok(())
 }
 
 /// Generate the types file.
-pub fn generate(filename: &str, out_dir: &str) -> Result<(), error::Error> {
+pub(crate) fn generate(filename: &str, out_dir: &str) -> Result<(), error::Error> {
     let mut fmt = srcgen::Formatter::new();
     emit_types(&mut fmt)?;
     fmt.update_file(filename, out_dir)?;
     Ok(())
 }
--- a/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/encodings.rs
@@ -13,17 +13,17 @@ use crate::shared::types::Reference::{R3
 use crate::shared::Definitions as SharedDefinitions;
 
 use super::recipes::RecipeGroup;
 
 fn enc(inst: impl Into<InstSpec>, recipe: EncodingRecipeNumber, bits: u16) -> EncodingBuilder {
     EncodingBuilder::new(inst.into(), recipe, bits)
 }
 
-pub struct PerCpuModeEncodings<'defs> {
+pub(crate) struct PerCpuModeEncodings<'defs> {
     pub inst_pred_reg: InstructionPredicateRegistry,
     pub enc32: Vec<Encoding>,
     pub enc64: Vec<Encoding>,
     recipes: &'defs Recipes,
 }
 
 impl<'defs> PerCpuModeEncodings<'defs> {
     fn new(recipes: &'defs Recipes) -> Self {
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs
@@ -1,29 +1,32 @@
 #![allow(non_snake_case)]
 
+use cranelift_codegen_shared::condcodes::IntCC;
 use std::collections::HashMap;
 
 use crate::cdsl::encodings::{Encoding, EncodingBuilder};
 use crate::cdsl::instructions::{
     InstSpec, Instruction, InstructionGroup, InstructionPredicate, InstructionPredicateNode,
     InstructionPredicateRegistry,
 };
 use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes};
 use crate::cdsl::settings::{SettingGroup, SettingPredicateNumber};
 use crate::cdsl::types::{LaneType, ValueType};
 use crate::shared::types::Bool::{B1, B16, B32, B64, B8};
 use crate::shared::types::Float::{F32, F64};
 use crate::shared::types::Int::{I16, I32, I64, I8};
 use crate::shared::types::Reference::{R32, R64};
 use crate::shared::Definitions as SharedDefinitions;
 
+use crate::isa::x86::opcodes::*;
+
 use super::recipes::{RecipeGroup, Template};
 
-pub struct PerCpuModeEncodings {
+pub(crate) struct PerCpuModeEncodings {
     pub enc32: Vec<Encoding>,
     pub enc64: Vec<Encoding>,
     pub recipes: Recipes,
     recipes_by_name: HashMap<String, EncodingRecipeNumber>,
     pub inst_pred_reg: InstructionPredicateRegistry,
 }
 
 impl PerCpuModeEncodings {
@@ -145,16 +148,30 @@ impl PerCpuModeEncodings {
 
         // REX-less encoding must come after REX encoding so we don't use it by default. Otherwise
         // reg-alloc would never use r8 and up.
         self.enc64(inst.bind(I32), template.rex());
         self.enc64(inst.bind(I32), template.nonrex());
         self.enc64(inst.bind(I64), template.rex().w());
     }
 
+    /// Add encodings for `inst.b32` to X86_32.
+    /// Add encodings for `inst.b32` to X86_64 with and without REX.
+    /// Add encodings for `inst.b64` to X86_64 with a REX.W prefix.
+    fn enc_b32_b64(&mut self, inst: impl Into<InstSpec>, template: Template) {
+        let inst: InstSpec = inst.into();
+        self.enc32(inst.bind(B32), template.nonrex());
+
+        // REX-less encoding must come after REX encoding so we don't use it by default. Otherwise
+        // reg-alloc would never use r8 and up.
+        self.enc64(inst.bind(B32), template.rex());
+        self.enc64(inst.bind(B32), template.nonrex());
+        self.enc64(inst.bind(B64), template.rex().w());
+    }
+
     /// Add encodings for `inst.i32` to X86_32.
     /// Add encodings for `inst.i32` to X86_64 with a REX prefix.
     /// Add encodings for `inst.i64` to X86_64 with a REX.W prefix.
     fn enc_i32_i64_rex_only(&mut self, inst: impl Into<InstSpec>, template: Template) {
         let inst: InstSpec = inst.into();
         self.enc32(inst.bind(I32), template.nonrex());
         self.enc64(inst.bind(I32), template.rex());
         self.enc64(inst.bind(I64), template.rex().w());
@@ -274,27 +291,47 @@ impl PerCpuModeEncodings {
         if w_bit {
             self.enc64(inst.clone().bind(I64).bind_any(), template.rex().w());
         } else {
             self.enc64(inst.clone().bind(I64).bind_any(), template.clone().rex());
             self.enc64(inst.clone().bind(I64).bind_any(), template);
         }
     }
 
+    /// Add the same encoding/template pairing to both X86_32 and X86_64
+    fn enc_32_64(&mut self, inst: impl Clone + Into<InstSpec>, template: Template) {
+        self.enc32(inst.clone(), template.clone());
+        self.enc64(inst, template);
+    }
+
     /// Add the same encoding/recipe pairing to both X86_32 and X86_64
     fn enc_32_64_rec(
         &mut self,
         inst: impl Clone + Into<InstSpec>,
         recipe: &EncodingRecipe,
         bits: u16,
     ) {
         self.enc32_rec(inst.clone(), recipe, bits);
         self.enc64_rec(inst, recipe, bits);
     }
 
+    /// Add the same encoding to both X86_32 and X86_64; assumes configuration (e.g. REX, operand binding) has already happened
+    fn enc_32_64_func<T>(
+        &mut self,
+        inst: impl Clone + Into<InstSpec>,
+        template: Template,
+        builder_closure: T,
+    ) where
+        T: FnOnce(EncodingBuilder) -> EncodingBuilder,
+    {
+        let encoding = self.make_encoding(inst.into(), template, builder_closure);
+        self.enc32.push(encoding.clone());
+        self.enc64.push(encoding);
+    }
+
     /// Add the same encoding to both X86_32 and X86_64; assumes configuration (e.g. REX, operand
     /// binding) has already happened.
     fn enc_32_64_maybe_isap(
         &mut self,
         inst: impl Clone + Into<InstSpec>,
         template: Template,
         isap: Option<SettingPredicateNumber>,
     ) {
@@ -534,16 +571,17 @@ pub(crate) fn define(
     let rec_furm_reg_to_ssa = r.template("furm_reg_to_ssa");
     let rec_furmi_rnd = r.template("furmi_rnd");
     let rec_get_pinned_reg = r.recipe("get_pinned_reg");
     let rec_got_fnaddr8 = r.template("got_fnaddr8");
     let rec_got_gvaddr8 = r.template("got_gvaddr8");
     let rec_gvaddr4 = r.template("gvaddr4");
     let rec_gvaddr8 = r.template("gvaddr8");
     let rec_icscc = r.template("icscc");
+    let rec_icscc_fpr = r.template("icscc_fpr");
     let rec_icscc_ib = r.template("icscc_ib");
     let rec_icscc_id = r.template("icscc_id");
     let rec_indirect_jmp = r.template("indirect_jmp");
     let rec_is_zero = r.template("is_zero");
     let rec_jmpb = r.template("jmpb");
     let rec_jmpd = r.template("jmpd");
     let rec_jt_base = r.template("jt_base");
     let rec_jt_entry = r.template("jt_entry");
@@ -617,16 +655,17 @@ pub(crate) fn define(
     let rec_u_id_z = r.template("u_id_z");
     let rec_umr = r.template("umr");
     let rec_umr_reg_to_ssa = r.template("umr_reg_to_ssa");
     let rec_ur = r.template("ur");
     let rec_urm = r.template("urm");
     let rec_urm_noflags = r.template("urm_noflags");
     let rec_urm_noflags_abcd = r.template("urm_noflags_abcd");
     let rec_vconst = r.template("vconst");
+    let rec_vconst_optimized = r.template("vconst_optimized");
 
     // Predicates shorthands.
     let all_ones_funcaddrs_and_not_is_pic =
         settings.predicate_by_name("all_ones_funcaddrs_and_not_is_pic");
     let is_pic = settings.predicate_by_name("is_pic");
     let not_all_ones_funcaddrs_and_not_is_pic =
         settings.predicate_by_name("not_all_ones_funcaddrs_and_not_is_pic");
     let not_is_pic = settings.predicate_by_name("not_is_pic");
@@ -639,867 +678,780 @@ pub(crate) fn define(
 
     // Definitions.
     let mut e = PerCpuModeEncodings::new();
 
     // The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing!
     e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0);
     e.enc_x86_64(
         set_pinned_reg.bind(I64),
-        rec_set_pinned_reg.opcodes(vec![0x89]).rex().w(),
+        rec_set_pinned_reg.opcodes(&MOV_STORE).rex().w(),
     );
 
-    e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01]));
-    e.enc_i32_i64(iadd_ifcout, rec_rout.opcodes(vec![0x01]));
-    e.enc_i32_i64(iadd_ifcin, rec_rin.opcodes(vec![0x11]));
-    e.enc_i32_i64(iadd_ifcarry, rec_rio.opcodes(vec![0x11]));
+    e.enc_i32_i64(iadd, rec_rr.opcodes(&ADD));
+    e.enc_i32_i64(iadd_ifcout, rec_rout.opcodes(&ADD));
+    e.enc_i32_i64(iadd_ifcin, rec_rin.opcodes(&ADC));
+    e.enc_i32_i64(iadd_ifcarry, rec_rio.opcodes(&ADC));
 
-    e.enc_i32_i64(isub, rec_rr.opcodes(vec![0x29]));
-    e.enc_i32_i64(isub_ifbout, rec_rout.opcodes(vec![0x29]));
-    e.enc_i32_i64(isub_ifbin, rec_rin.opcodes(vec![0x19]));
-    e.enc_i32_i64(isub_ifborrow, rec_rio.opcodes(vec![0x19]));
+    e.enc_i32_i64(isub, rec_rr.opcodes(&SUB));
+    e.enc_i32_i64(isub_ifbout, rec_rout.opcodes(&SUB));
+    e.enc_i32_i64(isub_ifbin, rec_rin.opcodes(&SBB));
+    e.enc_i32_i64(isub_ifborrow, rec_rio.opcodes(&SBB));
 
-    e.enc_i32_i64(band, rec_rr.opcodes(vec![0x21]));
-    e.enc_i32_i64(bor, rec_rr.opcodes(vec![0x09]));
-    e.enc_i32_i64(bxor, rec_rr.opcodes(vec![0x31]));
+    e.enc_i32_i64(band, rec_rr.opcodes(&AND));
+    e.enc_b32_b64(band, rec_rr.opcodes(&AND));
+    e.enc_i32_i64(bor, rec_rr.opcodes(&OR));
+    e.enc_b32_b64(bor, rec_rr.opcodes(&OR));
+    e.enc_i32_i64(bxor, rec_rr.opcodes(&XOR));
+    e.enc_b32_b64(bxor, rec_rr.opcodes(&XOR));
 
     // x86 has a bitwise not instruction NOT.
-    e.enc_i32_i64(bnot, rec_ur.opcodes(vec![0xf7]).rrr(2));
+    e.enc_i32_i64(bnot, rec_ur.opcodes(&NOT).rrr(2));
+    e.enc_b32_b64(bnot, rec_ur.opcodes(&NOT).rrr(2));
 
     // Also add a `b1` encodings for the logic instructions.
     // TODO: Should this be done with 8-bit instructions? It would improve partial register
     // dependencies.
-    e.enc_both(band.bind(B1), rec_rr.opcodes(vec![0x21]));
-    e.enc_both(bor.bind(B1), rec_rr.opcodes(vec![0x09]));
-    e.enc_both(bxor.bind(B1), rec_rr.opcodes(vec![0x31]));
+    e.enc_both(band.bind(B1), rec_rr.opcodes(&AND));
+    e.enc_both(bor.bind(B1), rec_rr.opcodes(&OR));
+    e.enc_both(bxor.bind(B1), rec_rr.opcodes(&XOR));
 
-    e.enc_i32_i64(imul, rec_rrx.opcodes(vec![0x0f, 0xaf]));
-    e.enc_i32_i64(x86_sdivmodx, rec_div.opcodes(vec![0xf7]).rrr(7));
-    e.enc_i32_i64(x86_udivmodx, rec_div.opcodes(vec![0xf7]).rrr(6));
+    e.enc_i32_i64(imul, rec_rrx.opcodes(&IMUL));
+    e.enc_i32_i64(x86_sdivmodx, rec_div.opcodes(&IDIV).rrr(7));
+    e.enc_i32_i64(x86_udivmodx, rec_div.opcodes(&DIV).rrr(6));
 
-    e.enc_i32_i64(x86_smulx, rec_mulx.opcodes(vec![0xf7]).rrr(5));
-    e.enc_i32_i64(x86_umulx, rec_mulx.opcodes(vec![0xf7]).rrr(4));
+    e.enc_i32_i64(x86_smulx, rec_mulx.opcodes(&IMUL_RDX_RAX).rrr(5));
+    e.enc_i32_i64(x86_umulx, rec_mulx.opcodes(&MUL).rrr(4));
 
-    e.enc_i32_i64(copy, rec_umr.opcodes(vec![0x89]));
-    e.enc_r32_r64_rex_only(copy, rec_umr.opcodes(vec![0x89]));
-    e.enc_both(copy.bind(B1), rec_umr.opcodes(vec![0x89]));
-    e.enc_both(copy.bind(I8), rec_umr.opcodes(vec![0x89]));
-    e.enc_both(copy.bind(I16), rec_umr.opcodes(vec![0x89]));
+    e.enc_i32_i64(copy, rec_umr.opcodes(&MOV_STORE));
+    e.enc_r32_r64_rex_only(copy, rec_umr.opcodes(&MOV_STORE));
+    e.enc_both(copy.bind(B1), rec_umr.opcodes(&MOV_STORE));
+    e.enc_both(copy.bind(I8), rec_umr.opcodes(&MOV_STORE));
+    e.enc_both(copy.bind(I16), rec_umr.opcodes(&MOV_STORE));
 
     // TODO For x86-64, only define REX forms for now, since we can't describe the
     // special regunit immediate operands with the current constraint language.
     for &ty in &[I8, I16, I32] {
-        e.enc32(regmove.bind(ty), rec_rmov.opcodes(vec![0x89]));
-        e.enc64(regmove.bind(ty), rec_rmov.opcodes(vec![0x89]).rex());
+        e.enc32(regmove.bind(ty), rec_rmov.opcodes(&MOV_STORE));
+        e.enc64(regmove.bind(ty), rec_rmov.opcodes(&MOV_STORE).rex());
+    }
+    for &ty in &[B8, B16, B32] {
+        e.enc32(regmove.bind(ty), rec_rmov.opcodes(&MOV_STORE));
+        e.enc64(regmove.bind(ty), rec_rmov.opcodes(&MOV_STORE).rex());
     }
-    e.enc64(regmove.bind(I64), rec_rmov.opcodes(vec![0x89]).rex().w());
-    e.enc_both(regmove.bind(B1), rec_rmov.opcodes(vec![0x89]));
-    e.enc_both(regmove.bind(I8), rec_rmov.opcodes(vec![0x89]));
-    e.enc32(regmove.bind_ref(R32), rec_rmov.opcodes(vec![0x89]));
-    e.enc64(regmove.bind_ref(R32), rec_rmov.opcodes(vec![0x89]).rex());
+    e.enc64(regmove.bind(I64), rec_rmov.opcodes(&MOV_STORE).rex().w());
+    e.enc64(regmove.bind(B64), rec_rmov.opcodes(&MOV_STORE).rex().w());
+    e.enc_both(regmove.bind(B1), rec_rmov.opcodes(&MOV_STORE));
+    e.enc_both(regmove.bind(I8), rec_rmov.opcodes(&MOV_STORE));
+    e.enc32(regmove.bind_ref(R32), rec_rmov.opcodes(&MOV_STORE));
+    e.enc64(regmove.bind_ref(R32), rec_rmov.opcodes(&MOV_STORE).rex());
     e.enc64(
         regmove.bind_ref(R64),
-        rec_rmov.opcodes(vec![0x89]).rex().w(),
+        rec_rmov.opcodes(&MOV_STORE).rex().w(),
     );
 
-    e.enc_i32_i64(iadd_imm, rec_r_ib.opcodes(vec![0x83]).rrr(0));
-    e.enc_i32_i64(iadd_imm, rec_r_id.opcodes(vec![0x81]).rrr(0));
+    e.enc_i32_i64(iadd_imm, rec_r_ib.opcodes(&ADD_IMM8_SIGN_EXTEND).rrr(0));
+    e.enc_i32_i64(iadd_imm, rec_r_id.opcodes(&ADD_IMM).rrr(0));
 
-    e.enc_i32_i64(band_imm, rec_r_ib.opcodes(vec![0x83]).rrr(4));
-    e.enc_i32_i64(band_imm, rec_r_id.opcodes(vec![0x81]).rrr(4));
+    e.enc_i32_i64(band_imm, rec_r_ib.opcodes(&AND_IMM8_SIGN_EXTEND).rrr(4));
+    e.enc_i32_i64(band_imm, rec_r_id.opcodes(&AND_IMM).rrr(4));
 
-    e.enc_i32_i64(bor_imm, rec_r_ib.opcodes(vec![0x83]).rrr(1));
-    e.enc_i32_i64(bor_imm, rec_r_id.opcodes(vec![0x81]).rrr(1));
+    e.enc_i32_i64(bor_imm, rec_r_ib.opcodes(&OR_IMM8_SIGN_EXTEND).rrr(1));
+    e.enc_i32_i64(bor_imm, rec_r_id.opcodes(&OR_IMM).rrr(1));
 
-    e.enc_i32_i64(bxor_imm, rec_r_ib.opcodes(vec![0x83]).rrr(6));
-    e.enc_i32_i64(bxor_imm, rec_r_id.opcodes(vec![0x81]).rrr(6));
+    e.enc_i32_i64(bxor_imm, rec_r_ib.opcodes(&XOR_IMM8_SIGN_EXTEND).rrr(6));
+    e.enc_i32_i64(bxor_imm, rec_r_id.opcodes(&XOR_IMM).rrr(6));
 
     // TODO: band_imm.i64 with an unsigned 32-bit immediate can be encoded as band_imm.i32. Can
     // even use the single-byte immediate for 0xffff_ffXX masks.
 
     // Immediate constants.
-    e.enc32(iconst.bind(I32), rec_pu_id.opcodes(vec![0xb8]));
+    e.enc32(iconst.bind(I32), rec_pu_id.opcodes(&MOV_IMM));
 
-    e.enc64(iconst.bind(I32), rec_pu_id.rex().opcodes(vec![0xb8]));
-    e.enc64(iconst.bind(I32), rec_pu_id.opcodes(vec![0xb8]));
+    e.enc64(iconst.bind(I32), rec_pu_id.rex().opcodes(&MOV_IMM));
+    e.enc64(iconst.bind(I32), rec_pu_id.opcodes(&MOV_IMM));
 
     // The 32-bit immediate movl also zero-extends to 64 bits.
     let f_unary_imm = formats.get(formats.by_name("UnaryImm"));
     let is_unsigned_int32 = InstructionPredicate::new_is_unsigned_int(f_unary_imm, "imm", 32, 0);
 
     e.enc64_func(
         iconst.bind(I64),
-        rec_pu_id.opcodes(vec![0xb8]).rex(),
+        rec_pu_id.opcodes(&MOV_IMM).rex(),
         |encoding| encoding.inst_predicate(is_unsigned_int32.clone()),
     );
-    e.enc64_func(
-        iconst.bind(I64),
-        rec_pu_id.opcodes(vec![0xb8]),
-        |encoding| encoding.inst_predicate(is_unsigned_int32),
-    );
+    e.enc64_func(iconst.bind(I64), rec_pu_id.opcodes(&MOV_IMM), |encoding| {
+        encoding.inst_predicate(is_unsigned_int32)
+    });
 
     // Sign-extended 32-bit immediate.
     e.enc64(
         iconst.bind(I64),
-        rec_u_id.rex().opcodes(vec![0xc7]).rrr(0).w(),
+        rec_u_id.rex().opcodes(&MOV_IMM_SIGNEXTEND).rrr(0).w(),
     );
 
-    // Finally, the 0xb8 opcode takes an 8-byte immediate with a REX.W prefix.
-    e.enc64(iconst.bind(I64), rec_pu_iq.opcodes(vec![0xb8]).rex().w());
+    // Finally, the MOV_IMM opcode takes an 8-byte immediate with a REX.W prefix.
+    e.enc64(iconst.bind(I64), rec_pu_iq.opcodes(&MOV_IMM).rex().w());
 
     // Bool constants (uses MOV)
     for &ty in &[B1, B8, B16, B32] {
-        e.enc_both(bconst.bind(ty), rec_pu_id_bool.opcodes(vec![0xb8]));
+        e.enc_both(bconst.bind(ty), rec_pu_id_bool.opcodes(&MOV_IMM));
     }
-    e.enc64(bconst.bind(B64), rec_pu_id_bool.opcodes(vec![0xb8]).rex());
+    e.enc64(bconst.bind(B64), rec_pu_id_bool.opcodes(&MOV_IMM).rex());
 
     let is_zero_int = InstructionPredicate::new_is_zero_int(f_unary_imm, "imm");
     e.enc_both_instp(
         iconst.bind(I8),
-        rec_u_id_z.opcodes(vec![0x30]),
+        rec_u_id_z.opcodes(&XORB),
         is_zero_int.clone(),
     );
     // You may expect that i16 encodings would have an 0x66 prefix on the opcode to indicate that
     // encodings should be on 16-bit operands (f.ex, "xor %ax, %ax"). Cranelift currently does not
     // know that it can drop the 0x66 prefix and clear the upper half of a 32-bit register in these
     // scenarios, so we explicitly select a wider but permissible opcode.
     //
     // This effectively formalizes the i16->i32 widening that Cranelift performs when there isn't
     // an appropriate i16 encoding available.
     e.enc_both_instp(
         iconst.bind(I16),
-        rec_u_id_z.opcodes(vec![0x31]),
+        rec_u_id_z.opcodes(&XOR),
         is_zero_int.clone(),
     );
     e.enc_both_instp(
         iconst.bind(I32),
-        rec_u_id_z.opcodes(vec![0x31]),
+        rec_u_id_z.opcodes(&XOR),
         is_zero_int.clone(),
     );
-    e.enc_x86_64_instp(
-        iconst.bind(I64),
-        rec_u_id_z.opcodes(vec![0x31]),
-        is_zero_int,
-    );
+    e.enc_x86_64_instp(iconst.bind(I64), rec_u_id_z.opcodes(&XOR), is_zero_int);
 
     // Shifts and rotates.
     // Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
     // and 16-bit shifts would need explicit masking.
 
     for &(inst, rrr) in &[(rotl, 0), (rotr, 1), (ishl, 4), (ushr, 5), (sshr, 7)] {
         // Cannot use enc_i32_i64 for this pattern because instructions require
         // to bind any.
         e.enc32(
             inst.bind(I32).bind_any(),
-            rec_rc.opcodes(vec![0xd3]).rrr(rrr),
+            rec_rc.opcodes(&ROTATE_CL).rrr(rrr),
         );
         e.enc64(
             inst.bind(I64).bind_any(),
-            rec_rc.opcodes(vec![0xd3]).rrr(rrr).rex().w(),
+            rec_rc.opcodes(&ROTATE_CL).rrr(rrr).rex().w(),
         );
         e.enc64(
             inst.bind(I32).bind_any(),
-            rec_rc.opcodes(vec![0xd3]).rrr(rrr).rex(),
+            rec_rc.opcodes(&ROTATE_CL).rrr(rrr).rex(),
         );
         e.enc64(
             inst.bind(I32).bind_any(),
-            rec_rc.opcodes(vec![0xd3]).rrr(rrr),
+            rec_rc.opcodes(&ROTATE_CL).rrr(rrr),
         );
     }
 
-    for &(inst, rrr) in &[
-        (rotl_imm, 0),
-        (rotr_imm, 1),
-        (ishl_imm, 4),
-        (ushr_imm, 5),
-        (sshr_imm, 7),
-    ] {
-        e.enc_i32_i64(inst, rec_r_ib.opcodes(vec![0xc1]).rrr(rrr));
-    }
+    e.enc_i32_i64(rotl_imm, rec_r_ib.opcodes(&ROTATE_IMM8).rrr(0));
+    e.enc_i32_i64(rotr_imm, rec_r_ib.opcodes(&ROTATE_IMM8).rrr(1));
+    e.enc_i32_i64(ishl_imm, rec_r_ib.opcodes(&ROTATE_IMM8).rrr(4));
+    e.enc_i32_i64(ushr_imm, rec_r_ib.opcodes(&ROTATE_IMM8).rrr(5));
+    e.enc_i32_i64(sshr_imm, rec_r_ib.opcodes(&ROTATE_IMM8).rrr(7));
 
     // Population count.
-    e.enc32_isap(
-        popcnt.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xb8]),
+    e.enc32_isap(popcnt.bind(I32), rec_urm.opcodes(&POPCNT), use_popcnt);
+    e.enc64_isap(
+        popcnt.bind(I64),
+        rec_urm.opcodes(&POPCNT).rex().w(),
         use_popcnt,
     );
-    e.enc64_isap(
-        popcnt.bind(I64),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xb8]).rex().w(),
-        use_popcnt,
-    );
-    e.enc64_isap(
-        popcnt.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xb8]).rex(),
-        use_popcnt,
-    );
-    e.enc64_isap(
-        popcnt.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xb8]),
-        use_popcnt,
-    );
+    e.enc64_isap(popcnt.bind(I32), rec_urm.opcodes(&POPCNT).rex(), use_popcnt);
+    e.enc64_isap(popcnt.bind(I32), rec_urm.opcodes(&POPCNT), use_popcnt);
 
     // Count leading zero bits.
-    e.enc32_isap(
-        clz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbd]),
-        use_lzcnt,
-    );
-    e.enc64_isap(
-        clz.bind(I64),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbd]).rex().w(),
-        use_lzcnt,
-    );
-    e.enc64_isap(
-        clz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbd]).rex(),
-        use_lzcnt,
-    );
-    e.enc64_isap(
-        clz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbd]),
-        use_lzcnt,
-    );
+    e.enc32_isap(clz.bind(I32), rec_urm.opcodes(&LZCNT), use_lzcnt);
+    e.enc64_isap(clz.bind(I64), rec_urm.opcodes(&LZCNT).rex().w(), use_lzcnt);
+    e.enc64_isap(clz.bind(I32), rec_urm.opcodes(&LZCNT).rex(), use_lzcnt);
+    e.enc64_isap(clz.bind(I32), rec_urm.opcodes(&LZCNT), use_lzcnt);
 
     // Count trailing zero bits.
-    e.enc32_isap(
-        ctz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbc]),
-        use_bmi1,
-    );
-    e.enc64_isap(
-        ctz.bind(I64),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbc]).rex().w(),
-        use_bmi1,
-    );
-    e.enc64_isap(
-        ctz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbc]).rex(),
-        use_bmi1,
-    );
-    e.enc64_isap(
-        ctz.bind(I32),
-        rec_urm.opcodes(vec![0xf3, 0x0f, 0xbc]),
-        use_bmi1,
-    );
+    e.enc32_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT), use_bmi1);
+    e.enc64_isap(ctz.bind(I64), rec_urm.opcodes(&TZCNT).rex().w(), use_bmi1);
+    e.enc64_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT).rex(), use_bmi1);
+    e.enc64_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT), use_bmi1);
 
     // Loads and stores.
     let f_load_complex = formats.get(formats.by_name("LoadComplex"));
     let is_load_complex_length_two = InstructionPredicate::new_length_equals(f_load_complex, 2);
 
     for recipe in &[rec_ldWithIndex, rec_ldWithIndexDisp8, rec_ldWithIndexDisp32] {
         e.enc_i32_i64_instp(
             load_complex,
-            recipe.opcodes(vec![0x8b]),
+            recipe.opcodes(&MOV_LOAD),
             is_load_complex_length_two.clone(),
         );
         e.enc_x86_64_instp(
             uload32_complex,
-            recipe.opcodes(vec![0x8b]),
+            recipe.opcodes(&MOV_LOAD),
             is_load_complex_length_two.clone(),
         );
 
         e.enc64_instp(
             sload32_complex,
-            recipe.opcodes(vec![0x63]).rex().w(),
+            recipe.opcodes(&MOVSXD).rex().w(),
             is_load_complex_length_two.clone(),
         );
 
         e.enc_i32_i64_instp(
             uload16_complex,
-            recipe.opcodes(vec![0x0f, 0xb7]),
+            recipe.opcodes(&MOVZX_WORD),
             is_load_complex_length_two.clone(),
         );
         e.enc_i32_i64_instp(
             sload16_complex,
-            recipe.opcodes(vec![0x0f, 0xbf]),
+            recipe.opcodes(&MOVSX_WORD),
             is_load_complex_length_two.clone(),
         );
 
         e.enc_i32_i64_instp(
             uload8_complex,
-            recipe.opcodes(vec![0x0f, 0xb6]),
+            recipe.opcodes(&MOVZX_BYTE),
             is_load_complex_length_two.clone(),
         );
 
         e.enc_i32_i64_instp(
             sload8_complex,
-            recipe.opcodes(vec![0x0f, 0xbe]),
+            recipe.opcodes(&MOVSX_BYTE),
             is_load_complex_length_two.clone(),
         );
     }
 
     let f_store_complex = formats.get(formats.by_name("StoreComplex"));
     let is_store_complex_length_three = InstructionPredicate::new_length_equals(f_store_complex, 3);
 
     for recipe in &[rec_stWithIndex, rec_stWithIndexDisp8, rec_stWithIndexDisp32] {
         e.enc_i32_i64_instp(
             store_complex,
-            recipe.opcodes(vec![0x89]),
+            recipe.opcodes(&MOV_STORE),
             is_store_complex_length_three.clone(),
         );
         e.enc_x86_64_instp(
             istore32_complex,
-            recipe.opcodes(vec![0x89]),
+            recipe.opcodes(&MOV_STORE),
             is_store_complex_length_three.clone(),
         );
         e.enc_both_instp(
             istore16_complex.bind(I32),
-            recipe.opcodes(vec![0x66, 0x89]),
+            recipe.opcodes(&MOV_STORE_16),
             is_store_complex_length_three.clone(),
         );
         e.enc_x86_64_instp(
             istore16_complex.bind(I64),
-            recipe.opcodes(vec![0x66, 0x89]),
+            recipe.opcodes(&MOV_STORE_16),
             is_store_complex_length_three.clone(),
         );
     }
 
     for recipe in &[
         rec_stWithIndex_abcd,
         rec_stWithIndexDisp8_abcd,
         rec_stWithIndexDisp32_abcd,
     ] {
         e.enc_both_instp(
             istore8_complex.bind(I32),
-            recipe.opcodes(vec![0x88]),
+            recipe.opcodes(&MOV_BYTE_STORE),
             is_store_complex_length_three.clone(),
         );
         e.enc_x86_64_instp(
             istore8_complex.bind(I64),
-            recipe.opcodes(vec![0x88]),
+            recipe.opcodes(&MOV_BYTE_STORE),
             is_store_complex_length_three.clone(),
         );
     }
 
     for recipe in &[rec_st, rec_stDisp8, rec_stDisp32] {
-        e.enc_i32_i64_ld_st(store, true, recipe.opcodes(vec![0x89]));
-        e.enc_x86_64(istore32.bind(I64).bind_any(), recipe.opcodes(vec![0x89]));
-        e.enc_i32_i64_ld_st(istore16, false, recipe.opcodes(vec![0x66, 0x89]));
+        e.enc_i32_i64_ld_st(store, true, recipe.opcodes(&MOV_STORE));
+        e.enc_x86_64(istore32.bind(I64).bind_any(), recipe.opcodes(&MOV_STORE));
+        e.enc_i32_i64_ld_st(istore16, false, recipe.opcodes(&MOV_STORE_16));
     }
 
     // Byte stores are more complicated because the registers they can address
     // depends of the presence of a REX prefix. The st*_abcd recipes fall back to
     // the corresponding st* recipes when a REX prefix is applied.
 
     for recipe in &[rec_st_abcd, rec_stDisp8_abcd, rec_stDisp32_abcd] {
-        e.enc_both(istore8.bind(I32).bind_any(), recipe.opcodes(vec![0x88]));
-        e.enc_x86_64(istore8.bind(I64).bind_any(), recipe.opcodes(vec![0x88]));
+        e.enc_both(
+            istore8.bind(I32).bind_any(),
+            recipe.opcodes(&MOV_BYTE_STORE),
+        );
+        e.enc_x86_64(
+            istore8.bind(I64).bind_any(),
+            recipe.opcodes(&MOV_BYTE_STORE),
+        );
     }
 
-    e.enc_i32_i64(spill, rec_spillSib32.opcodes(vec![0x89]));
-    e.enc_i32_i64(regspill, rec_regspill32.opcodes(vec![0x89]));
-    e.enc_r32_r64_rex_only(spill, rec_spillSib32.opcodes(vec![0x89]));
-    e.enc_r32_r64_rex_only(regspill, rec_regspill32.opcodes(vec![0x89]));
+    e.enc_i32_i64(spill, rec_spillSib32.opcodes(&MOV_STORE));
+    e.enc_i32_i64(regspill, rec_regspill32.opcodes(&MOV_STORE));
+    e.enc_r32_r64_rex_only(spill, rec_spillSib32.opcodes(&MOV_STORE));
+    e.enc_r32_r64_rex_only(regspill, rec_regspill32.opcodes(&MOV_STORE));
 
     // Use a 32-bit write for spilling `b1`, `i8` and `i16` to avoid
     // constraining the permitted registers.
     // See MIN_SPILL_SLOT_SIZE which makes this safe.
 
-    e.enc_both(spill.bind(B1), rec_spillSib32.opcodes(vec![0x89]));
-    e.enc_both(regspill.bind(B1), rec_regspill32.opcodes(vec![0x89]));
+    e.enc_both(spill.bind(B1), rec_spillSib32.opcodes(&MOV_STORE));
+    e.enc_both(regspill.bind(B1), rec_regspill32.opcodes(&MOV_STORE));
     for &ty in &[I8, I16] {
-        e.enc_both(spill.bind(ty), rec_spillSib32.opcodes(vec![0x89]));
-        e.enc_both(regspill.bind(ty), rec_regspill32.opcodes(vec![0x89]));
+        e.enc_both(spill.bind(ty), rec_spillSib32.opcodes(&MOV_STORE));
+        e.enc_both(regspill.bind(ty), rec_regspill32.opcodes(&MOV_STORE));
     }
 
     for recipe in &[rec_ld, rec_ldDisp8, rec_ldDisp32] {
-        e.enc_i32_i64_ld_st(load, true, recipe.opcodes(vec![0x8b]));
-        e.enc_x86_64(uload32.bind(I64), recipe.opcodes(vec![0x8b]));
-        e.enc64(sload32.bind(I64), recipe.opcodes(vec![0x63]).rex().w());
-        e.enc_i32_i64_ld_st(uload16, true, recipe.opcodes(vec![0x0f, 0xb7]));
-        e.enc_i32_i64_ld_st(sload16, true, recipe.opcodes(vec![0x0f, 0xbf]));
-        e.enc_i32_i64_ld_st(uload8, true, recipe.opcodes(vec![0x0f, 0xb6]));
-        e.enc_i32_i64_ld_st(sload8, true, recipe.opcodes(vec![0x0f, 0xbe]));
+        e.enc_i32_i64_ld_st(load, true, recipe.opcodes(&MOV_LOAD));
+        e.enc_x86_64(uload32.bind(I64), recipe.opcodes(&MOV_LOAD));
+        e.enc64(sload32.bind(I64), recipe.opcodes(&MOVSXD).rex().w());
+        e.enc_i32_i64_ld_st(uload16, true, recipe.opcodes(&MOVZX_WORD));
+        e.enc_i32_i64_ld_st(sload16, true, recipe.opcodes(&MOVSX_WORD));
+        e.enc_i32_i64_ld_st(uload8, true, recipe.opcodes(&MOVZX_BYTE));
+        e.enc_i32_i64_ld_st(sload8, true, recipe.opcodes(&MOVSX_BYTE));
     }
 
-    e.enc_i32_i64(fill, rec_fillSib32.opcodes(vec![0x8b]));
-    e.enc_i32_i64(regfill, rec_regfill32.opcodes(vec![0x8b]));
-    e.enc_r32_r64_rex_only(fill, rec_fillSib32.opcodes(vec![0x8b]));
-    e.enc_r32_r64_rex_only(regfill, rec_regfill32.opcodes(vec![0x8b]));
+    e.enc_i32_i64(fill, rec_fillSib32.opcodes(&MOV_LOAD));
+    e.enc_i32_i64(regfill, rec_regfill32.opcodes(&MOV_LOAD));
+    e.enc_r32_r64_rex_only(fill, rec_fillSib32.opcodes(&MOV_LOAD));
+    e.enc_r32_r64_rex_only(regfill, rec_regfill32.opcodes(&MOV_LOAD));
 
     // No-op fills, created by late-stage redundant-fill removal.
     for &ty in &[I64, I32, I16, I8] {
         e.enc64_rec(fill_nop.bind(ty), rec_fillnull, 0);
         e.enc32_rec(fill_nop.bind(ty), rec_fillnull, 0);
     }
     e.enc64_rec(fill_nop.bind(B1), rec_fillnull, 0);
     e.enc32_rec(fill_nop.bind(B1), rec_fillnull, 0);
     for &ty in &[F64, F32] {
         e.enc64_rec(fill_nop.bind(ty), rec_ffillnull, 0);
         e.enc32_rec(fill_nop.bind(ty), rec_ffillnull, 0);
     }
 
     // Load 32 bits from `b1`, `i8` and `i16` spill slots. See `spill.b1` above.
 
-    e.enc_both(fill.bind(B1), rec_fillSib32.opcodes(vec![0x8b]));
-    e.enc_both(regfill.bind(B1), rec_regfill32.opcodes(vec![0x8b]));
+    e.enc_both(fill.bind(B1), rec_fillSib32.opcodes(&MOV_LOAD));
+    e.enc_both(regfill.bind(B1), rec_regfill32.opcodes(&MOV_LOAD));
     for &ty in &[I8, I16] {
-        e.enc_both(fill.bind(ty), rec_fillSib32.opcodes(vec![0x8b]));
-        e.enc_both(regfill.bind(ty), rec_regfill32.opcodes(vec![0x8b]));
+        e.enc_both(fill.bind(ty), rec_fillSib32.opcodes(&MOV_LOAD));
+        e.enc_both(regfill.bind(ty), rec_regfill32.opcodes(&MOV_LOAD));
     }
 
     // Push and Pop.
-    e.enc32(x86_push.bind(I32), rec_pushq.opcodes(vec![0x50]));
-    e.enc_x86_64(x86_push.bind(I64), rec_pushq.opcodes(vec![0x50]));
+    e.enc32(x86_push.bind(I32), rec_pushq.opcodes(&PUSH_REG));
+    e.enc_x86_64(x86_push.bind(I64), rec_pushq.opcodes(&PUSH_REG));
 
-    e.enc32(x86_pop.bind(I32), rec_popq.opcodes(vec![0x58]));
-    e.enc_x86_64(x86_pop.bind(I64), rec_popq.opcodes(vec![0x58]));
+    e.enc32(x86_pop.bind(I32), rec_popq.opcodes(&POP_REG));
+    e.enc_x86_64(x86_pop.bind(I64), rec_popq.opcodes(&POP_REG));
 
     // Copy Special
     // For x86-64, only define REX forms for now, since we can't describe the
     // special regunit immediate operands with the current constraint language.
-    e.enc64(copy_special, rec_copysp.opcodes(vec![0x89]).rex().w());
-    e.enc32(copy_special, rec_copysp.opcodes(vec![0x89]));
+    e.enc64(copy_special, rec_copysp.opcodes(&MOV_STORE).rex().w());
+    e.enc32(copy_special, rec_copysp.opcodes(&MOV_STORE));
 
     // Copy to SSA.  These have to be done with special _rex_only encoders, because the standard
     // machinery for deciding whether a REX.{RXB} prefix is needed doesn't take into account
     // the source register, which is specified directly in the instruction.
-    e.enc_i32_i64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89]));
-    e.enc_r32_r64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(vec![0x89]));
-    e.enc_both_rex_only(copy_to_ssa.bind(B1), rec_umr_reg_to_ssa.opcodes(vec![0x89]));
-    e.enc_both_rex_only(copy_to_ssa.bind(I8), rec_umr_reg_to_ssa.opcodes(vec![0x89]));
+    e.enc_i32_i64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(&MOV_STORE));
+    e.enc_r32_r64_rex_only(copy_to_ssa, rec_umr_reg_to_ssa.opcodes(&MOV_STORE));
+    e.enc_both_rex_only(copy_to_ssa.bind(B1), rec_umr_reg_to_ssa.opcodes(&MOV_STORE));
+    e.enc_both_rex_only(copy_to_ssa.bind(I8), rec_umr_reg_to_ssa.opcodes(&MOV_STORE));
     e.enc_both_rex_only(
         copy_to_ssa.bind(I16),
-        rec_umr_reg_to_ssa.opcodes(vec![0x89]),
+        rec_umr_reg_to_ssa.opcodes(&MOV_STORE),
     );
     e.enc_both_rex_only(
         copy_to_ssa.bind(F64),
-        rec_furm_reg_to_ssa.opcodes(vec![0xf2, 0x0f, 0x10]),
+        rec_furm_reg_to_ssa.opcodes(&MOVSD_LOAD),
     );
     e.enc_both_rex_only(
         copy_to_ssa.bind(F32),
-        rec_furm_reg_to_ssa.opcodes(vec![0xf3, 0x0f, 0x10]),
+        rec_furm_reg_to_ssa.opcodes(&MOVSS_LOAD),
     );
 
     // Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
     // into a no-op.
     // The same encoding is generated for both the 64- and 32-bit architectures.
     for &ty in &[I64, I32, I16, I8] {
         e.enc64_rec(copy_nop.bind(ty), rec_stacknull, 0);
         e.enc32_rec(copy_nop.bind(ty), rec_stacknull, 0);
     }
     for &ty in &[F64, F32] {
         e.enc64_rec(copy_nop.bind(ty), rec_stacknull, 0);
         e.enc32_rec(copy_nop.bind(ty), rec_stacknull, 0);
     }
 
     // Adjust SP down by a dynamic value (or up, with a negative operand).
-    e.enc32(adjust_sp_down.bind(I32), rec_adjustsp.opcodes(vec![0x29]));
+    e.enc32(adjust_sp_down.bind(I32), rec_adjustsp.opcodes(&SUB));
     e.enc64(
         adjust_sp_down.bind(I64),
-        rec_adjustsp.opcodes(vec![0x29]).rex().w(),
+        rec_adjustsp.opcodes(&SUB).rex().w(),
     );
 
     // Adjust SP up by an immediate (or down, with a negative immediate).
-    e.enc32(adjust_sp_up_imm, rec_adjustsp_ib.opcodes(vec![0x83]));
-    e.enc32(adjust_sp_up_imm, rec_adjustsp_id.opcodes(vec![0x81]));
+    e.enc32(adjust_sp_up_imm, rec_adjustsp_ib.opcodes(&CMP_IMM8));
+    e.enc32(adjust_sp_up_imm, rec_adjustsp_id.opcodes(&CMP_IMM));
     e.enc64(
         adjust_sp_up_imm,
-        rec_adjustsp_ib.opcodes(vec![0x83]).rex().w(),
+        rec_adjustsp_ib.opcodes(&CMP_IMM8).rex().w(),
     );
     e.enc64(
         adjust_sp_up_imm,
-        rec_adjustsp_id.opcodes(vec![0x81]).rex().w(),
+        rec_adjustsp_id.opcodes(&CMP_IMM).rex().w(),
     );
 
     // Adjust SP down by an immediate (or up, with a negative immediate).
     e.enc32(
         adjust_sp_down_imm,
-        rec_adjustsp_ib.opcodes(vec![0x83]).rrr(5),
+        rec_adjustsp_ib.opcodes(&CMP_IMM8).rrr(5),
     );
-    e.enc32(
-        adjust_sp_down_imm,
-        rec_adjustsp_id.opcodes(vec![0x81]).rrr(5),
-    );
+    e.enc32(adjust_sp_down_imm, rec_adjustsp_id.opcodes(&CMP_IMM).rrr(5));
     e.enc64(
         adjust_sp_down_imm,
-        rec_adjustsp_ib.opcodes(vec![0x83]).rrr(5).rex().w(),
+        rec_adjustsp_ib.opcodes(&CMP_IMM8).rrr(5).rex().w(),
     );
     e.enc64(
         adjust_sp_down_imm,
-        rec_adjustsp_id.opcodes(vec![0x81]).rrr(5).rex().w(),
+        rec_adjustsp_id.opcodes(&CMP_IMM).rrr(5).rex().w(),
     );
 
     // Float loads and stores.
-    e.enc_both(
-        load.bind(F32).bind_any(),
-        rec_fld.opcodes(vec![0xf3, 0x0f, 0x10]),
-    );
+    e.enc_both(load.bind(F32).bind_any(), rec_fld.opcodes(&MOVSS_LOAD));
+    e.enc_both(load.bind(F32).bind_any(), rec_fldDisp8.opcodes(&MOVSS_LOAD));
     e.enc_both(
         load.bind(F32).bind_any(),
-        rec_fldDisp8.opcodes(vec![0xf3, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        load.bind(F32).bind_any(),
-        rec_fldDisp32.opcodes(vec![0xf3, 0x0f, 0x10]),
+        rec_fldDisp32.opcodes(&MOVSS_LOAD),
     );
 
     e.enc_both(
         load_complex.bind(F32),
-        rec_fldWithIndex.opcodes(vec![0xf3, 0x0f, 0x10]),
+        rec_fldWithIndex.opcodes(&MOVSS_LOAD),
     );
     e.enc_both(
         load_complex.bind(F32),
-        rec_fldWithIndexDisp8.opcodes(vec![0xf3, 0x0f, 0x10]),
+        rec_fldWithIndexDisp8.opcodes(&MOVSS_LOAD),
     );
     e.enc_both(
         load_complex.bind(F32),
-        rec_fldWithIndexDisp32.opcodes(vec![0xf3, 0x0f, 0x10]),
+        rec_fldWithIndexDisp32.opcodes(&MOVSS_LOAD),
     );
 
+    e.enc_both(load.bind(F64).bind_any(), rec_fld.opcodes(&MOVSD_LOAD));
+    e.enc_both(load.bind(F64).bind_any(), rec_fldDisp8.opcodes(&MOVSD_LOAD));
     e.enc_both(
         load.bind(F64).bind_any(),
-        rec_fld.opcodes(vec![0xf2, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        load.bind(F64).bind_any(),
-        rec_fldDisp8.opcodes(vec![0xf2, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        load.bind(F64).bind_any(),
-        rec_fldDisp32.opcodes(vec![0xf2, 0x0f, 0x10]),
+        rec_fldDisp32.opcodes(&MOVSD_LOAD),
     );
 
     e.enc_both(
         load_complex.bind(F64),
-        rec_fldWithIndex.opcodes(vec![0xf2, 0x0f, 0x10]),
+        rec_fldWithIndex.opcodes(&MOVSD_LOAD),
     );
     e.enc_both(
         load_complex.bind(F64),
-        rec_fldWithIndexDisp8.opcodes(vec![0xf2, 0x0f, 0x10]),
+        rec_fldWithIndexDisp8.opcodes(&MOVSD_LOAD),
     );
     e.enc_both(
         load_complex.bind(F64),
-        rec_fldWithIndexDisp32.opcodes(vec![0xf2, 0x0f, 0x10]),
+        rec_fldWithIndexDisp32.opcodes(&MOVSD_LOAD),
     );
 
+    e.enc_both(store.bind(F32).bind_any(), rec_fst.opcodes(&MOVSS_STORE));
     e.enc_both(
         store.bind(F32).bind_any(),
-        rec_fst.opcodes(vec![0xf3, 0x0f, 0x11]),
+        rec_fstDisp8.opcodes(&MOVSS_STORE),
     );
     e.enc_both(
         store.bind(F32).bind_any(),
-        rec_fstDisp8.opcodes(vec![0xf3, 0x0f, 0x11]),
-    );
-    e.enc_both(
-        store.bind(F32).bind_any(),
-        rec_fstDisp32.opcodes(vec![0xf3, 0x0f, 0x11]),
+        rec_fstDisp32.opcodes(&MOVSS_STORE),
     );
 
     e.enc_both(
         store_complex.bind(F32),
-        rec_fstWithIndex.opcodes(vec![0xf3, 0x0f, 0x11]),
+        rec_fstWithIndex.opcodes(&MOVSS_STORE),
     );
     e.enc_both(
         store_complex.bind(F32),
-        rec_fstWithIndexDisp8.opcodes(vec![0xf3, 0x0f, 0x11]),
+        rec_fstWithIndexDisp8.opcodes(&MOVSS_STORE),
     );
     e.enc_both(
         store_complex.bind(F32),
-        rec_fstWithIndexDisp32.opcodes(vec![0xf3, 0x0f, 0x11]),
+        rec_fstWithIndexDisp32.opcodes(&MOVSS_STORE),
     );
 
+    e.enc_both(store.bind(F64).bind_any(), rec_fst.opcodes(&MOVSD_STORE));
     e.enc_both(
         store.bind(F64).bind_any(),
-        rec_fst.opcodes(vec![0xf2, 0x0f, 0x11]),
+        rec_fstDisp8.opcodes(&MOVSD_STORE),
     );
     e.enc_both(
         store.bind(F64).bind_any(),
-        rec_fstDisp8.opcodes(vec![0xf2, 0x0f, 0x11]),
-    );
-    e.enc_both(
-        store.bind(F64).bind_any(),
-        rec_fstDisp32.opcodes(vec![0xf2, 0x0f, 0x11]),
+        rec_fstDisp32.opcodes(&MOVSD_STORE),
     );
 
     e.enc_both(
         store_complex.bind(F64),
-        rec_fstWithIndex.opcodes(vec![0xf2, 0x0f, 0x11]),
+        rec_fstWithIndex.opcodes(&MOVSD_STORE),
     );
     e.enc_both(
         store_complex.bind(F64),
-        rec_fstWithIndexDisp8.opcodes(vec![0xf2, 0x0f, 0x11]),
+        rec_fstWithIndexDisp8.opcodes(&MOVSD_STORE),
     );
     e.enc_both(
         store_complex.bind(F64),
-        rec_fstWithIndexDisp32.opcodes(vec![0xf2, 0x0f, 0x11]),
+        rec_fstWithIndexDisp32.opcodes(&MOVSD_STORE),
     );
 
-    e.enc_both(
-        fill.bind(F32),
-        rec_ffillSib32.opcodes(vec![0xf3, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        regfill.bind(F32),
-        rec_fregfill32.opcodes(vec![0xf3, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        fill.bind(F64),
-        rec_ffillSib32.opcodes(vec![0xf2, 0x0f, 0x10]),
-    );
-    e.enc_both(
-        regfill.bind(F64),
-        rec_fregfill32.opcodes(vec![0xf2, 0x0f, 0x10]),
-    );
+    e.enc_both(fill.bind(F32), rec_ffillSib32.opcodes(&MOVSS_LOAD));
+    e.enc_both(regfill.bind(F32), rec_fregfill32.opcodes(&MOVSS_LOAD));
+    e.enc_both(fill.bind(F64), rec_ffillSib32.opcodes(&MOVSD_LOAD));
+    e.enc_both(regfill.bind(F64), rec_fregfill32.opcodes(&MOVSD_LOAD));
 
-    e.enc_both(
-        spill.bind(F32),
-        rec_fspillSib32.opcodes(vec![0xf3, 0x0f, 0x11]),
-    );
-    e.enc_both(
-        regspill.bind(F32),
-        rec_fregspill32.opcodes(vec![0xf3, 0x0f, 0x11]),
-    );
-    e.enc_both(
-        spill.bind(F64),
-        rec_fspillSib32.opcodes(vec![0xf2, 0x0f, 0x11]),
-    );
-    e.enc_both(
-        regspill.bind(F64),
-        rec_fregspill32.opcodes(vec![0xf2, 0x0f, 0x11]),
-    );
+    e.enc_both(spill.bind(F32), rec_fspillSib32.opcodes(&MOVSS_STORE));
+    e.enc_both(regspill.bind(F32), rec_fregspill32.opcodes(&MOVSS_STORE));
+    e.enc_both(spill.bind(F64), rec_fspillSib32.opcodes(&MOVSD_STORE));
+    e.enc_both(regspill.bind(F64), rec_fregspill32.opcodes(&MOVSD_STORE));
 
     // Function addresses.
 
     // Non-PIC, all-ones funcaddresses.
     e.enc32_isap(
         func_addr.bind(I32),
-        rec_fnaddr4.opcodes(vec![0xb8]),
+        rec_fnaddr4.opcodes(&MOV_IMM),
         not_all_ones_funcaddrs_and_not_is_pic,
     );
     e.enc64_isap(
         func_addr.bind(I64),
-        rec_fnaddr8.opcodes(vec![0xb8]).rex().w(),
+        rec_fnaddr8.opcodes(&MOV_IMM).rex().w(),
         not_all_ones_funcaddrs_and_not_is_pic,
     );
 
     // Non-PIC, all-zeros funcaddresses.
     e.enc32_isap(
         func_addr.bind(I32),
-        rec_allones_fnaddr4.opcodes(vec![0xb8]),
+        rec_allones_fnaddr4.opcodes(&MOV_IMM),
         all_ones_funcaddrs_and_not_is_pic,
     );
     e.enc64_isap(
         func_addr.bind(I64),
-        rec_allones_fnaddr8.opcodes(vec![0xb8]).rex().w(),
+        rec_allones_fnaddr8.opcodes(&MOV_IMM).rex().w(),
         all_ones_funcaddrs_and_not_is_pic,
     );
 
     // 64-bit, colocated, both PIC and non-PIC. Use the lea instruction's pc-relative field.
     let f_func_addr = formats.get(formats.by_name("FuncAddr"));
     let is_colocated_func = InstructionPredicate::new_is_colocated_func(f_func_addr, "func_ref");
     e.enc64_instp(
         func_addr.bind(I64),
-        rec_pcrel_fnaddr8.opcodes(vec![0x8d]).rex().w(),
+        rec_pcrel_fnaddr8.opcodes(&LEA).rex().w(),
         is_colocated_func,
     );
 
     // 64-bit, non-colocated, PIC.
     e.enc64_isap(
         func_addr.bind(I64),
-        rec_got_fnaddr8.opcodes(vec![0x8b]).rex().w(),
+        rec_got_fnaddr8.opcodes(&MOV_LOAD).rex().w(),
         is_pic,
     );
 
     // Global addresses.
 
     // Non-PIC.
     e.enc32_isap(
         symbol_value.bind(I32),
-        rec_gvaddr4.opcodes(vec![0xb8]),
+        rec_gvaddr4.opcodes(&MOV_IMM),
         not_is_pic,
     );
     e.enc64_isap(
         symbol_value.bind(I64),
-        rec_gvaddr8.opcodes(vec![0xb8]).rex().w(),
+        rec_gvaddr8.opcodes(&MOV_IMM).rex().w(),
         not_is_pic,
     );
 
     // PIC, colocated.
     e.enc64_func(
         symbol_value.bind(I64),
-        rec_pcrel_gvaddr8.opcodes(vec![0x8d]).rex().w(),
+        rec_pcrel_gvaddr8.opcodes(&LEA).rex().w(),
         |encoding| {
             encoding
                 .isa_predicate(is_pic)
                 .inst_predicate(InstructionPredicate::new_is_colocated_data(formats))
         },
     );
 
     // PIC, non-colocated.
     e.enc64_isap(
         symbol_value.bind(I64),
-        rec_got_gvaddr8.opcodes(vec![0x8b]).rex().w(),
+        rec_got_gvaddr8.opcodes(&MOV_LOAD).rex().w(),
         is_pic,
     );
 
     // Stack addresses.
     //
     // TODO: Add encoding rules for stack_load and stack_store, so that they
     // don't get legalized to stack_addr + load/store.
-    e.enc32(stack_addr.bind(I32), rec_spaddr4_id.opcodes(vec![0x8d]));
-    e.enc64(
-        stack_addr.bind(I64),
-        rec_spaddr8_id.opcodes(vec![0x8d]).rex().w(),
-    );
+    e.enc32(stack_addr.bind(I32), rec_spaddr4_id.opcodes(&LEA));
+    e.enc64(stack_addr.bind(I64), rec_spaddr8_id.opcodes(&LEA).rex().w());
 
     // Call/return
 
     // 32-bit, both PIC and non-PIC.
-    e.enc32(call, rec_call_id.opcodes(vec![0xe8]));
+    e.enc32(call, rec_call_id.opcodes(&CALL_RELATIVE));
 
     // 64-bit, colocated, both PIC and non-PIC. Use the call instruction's pc-relative field.
     let f_call = formats.get(formats.by_name("Call"));
     let is_colocated_func = InstructionPredicate::new_is_colocated_func(f_call, "func_ref");
-    e.enc64_instp(call, rec_call_id.opcodes(vec![0xe8]), is_colocated_func);
+    e.enc64_instp(call, rec_call_id.opcodes(&CALL_RELATIVE), is_colocated_func);
 
     // 64-bit, non-colocated, PIC. There is no 64-bit non-colocated non-PIC version, since non-PIC
     // is currently using the large model, which requires calls be lowered to
     // func_addr+call_indirect.
-    e.enc64_isap(call, rec_call_plt_id.opcodes(vec![0xe8]), is_pic);
+    e.enc64_isap(call, rec_call_plt_id.opcodes(&CALL_RELATIVE), is_pic);
 
     e.enc32(
         call_indirect.bind(I32),
-        rec_call_r.opcodes(vec![0xff]).rrr(2),
+        rec_call_r.opcodes(&JUMP_ABSOLUTE).rrr(2),
     );
     e.enc64(
         call_indirect.bind(I64),
-        rec_call_r.opcodes(vec![0xff]).rrr(2).rex(),
+        rec_call_r.opcodes(&JUMP_ABSOLUTE).rrr(2).rex(),
     );
     e.enc64(
         call_indirect.bind(I64),
-        rec_call_r.opcodes(vec![0xff]).rrr(2),
+        rec_call_r.opcodes(&JUMP_ABSOLUTE).rrr(2),
     );
 
-    e.enc32(return_, rec_ret.opcodes(vec![0xc3]));
-    e.enc64(return_, rec_ret.opcodes(vec![0xc3]));
+    e.enc32(return_, rec_ret.opcodes(&RET_NEAR));
+    e.enc64(return_, rec_ret.opcodes(&RET_NEAR));
 
     // Branches.
-    e.enc32(jump, rec_jmpb.opcodes(vec![0xeb]));
-    e.enc64(jump, rec_jmpb.opcodes(vec![0xeb]));
-    e.enc32(jump, rec_jmpd.opcodes(vec![0xe9]));
-    e.enc64(jump, rec_jmpd.opcodes(vec![0xe9]));
+    e.enc32(jump, rec_jmpb.opcodes(&JUMP_SHORT));
+    e.enc64(jump, rec_jmpb.opcodes(&JUMP_SHORT));
+    e.enc32(jump, rec_jmpd.opcodes(&JUMP_NEAR_RELATIVE));
+    e.enc64(jump, rec_jmpd.opcodes(&JUMP_NEAR_RELATIVE));
 
-    e.enc_both(brif, rec_brib.opcodes(vec![0x70]));
-    e.enc_both(brif, rec_brid.opcodes(vec![0x0f, 0x80]));
+    e.enc_both(brif, rec_brib.opcodes(&JUMP_SHORT_IF_OVERFLOW));
+    e.enc_both(brif, rec_brid.opcodes(&JUMP_NEAR_IF_OVERFLOW));
 
     // Not all float condition codes are legal, see `supported_floatccs`.
-    e.enc_both(brff, rec_brfb.opcodes(vec![0x70]));
-    e.enc_both(brff, rec_brfd.opcodes(vec![0x0f, 0x80]));
+    e.enc_both(brff, rec_brfb.opcodes(&JUMP_SHORT_IF_OVERFLOW));
+    e.enc_both(brff, rec_brfd.opcodes(&JUMP_NEAR_IF_OVERFLOW));
 
     // Note that the tjccd opcode will be prefixed with 0x0f.
-    e.enc_i32_i64(brz, rec_tjccb.opcodes(vec![0x74]));
-    e.enc_i32_i64(brz, rec_tjccd.opcodes(vec![0x84]));
-    e.enc_i32_i64(brnz, rec_tjccb.opcodes(vec![0x75]));
-    e.enc_i32_i64(brnz, rec_tjccd.opcodes(vec![0x85]));
+    e.enc_i32_i64(brz, rec_tjccb.opcodes(&JUMP_SHORT_IF_EQUAL));
+    e.enc_i32_i64(brz, rec_tjccd.opcodes(&TEST_BYTE_REG));
+    e.enc_i32_i64(brnz, rec_tjccb.opcodes(&JUMP_SHORT_IF_NOT_EQUAL));
+    e.enc_i32_i64(brnz, rec_tjccd.opcodes(&TEST_REG));
 
     // Branch on a b1 value in a register only looks at the low 8 bits. See also
     // bint encodings below.
     //
     // Start with the worst-case encoding for X86_32 only. The register allocator
     // can't handle a branch with an ABCD-constrained operand.
-    e.enc32(brz.bind(B1), rec_t8jccd_long.opcodes(vec![0x84]));
-    e.enc32(brnz.bind(B1), rec_t8jccd_long.opcodes(vec![0x85]));
+    e.enc32(brz.bind(B1), rec_t8jccd_long.opcodes(&TEST_BYTE_REG));
+    e.enc32(brnz.bind(B1), rec_t8jccd_long.opcodes(&TEST_REG));
 
-    e.enc_both(brz.bind(B1), rec_t8jccb_abcd.opcodes(vec![0x74]));
-    e.enc_both(brz.bind(B1), rec_t8jccd_abcd.opcodes(vec![0x84]));
-    e.enc_both(brnz.bind(B1), rec_t8jccb_abcd.opcodes(vec![0x75]));
-    e.enc_both(brnz.bind(B1), rec_t8jccd_abcd.opcodes(vec![0x85]));
+    e.enc_both(brz.bind(B1), rec_t8jccb_abcd.opcodes(&JUMP_SHORT_IF_EQUAL));
+    e.enc_both(brz.bind(B1), rec_t8jccd_abcd.opcodes(&TEST_BYTE_REG));
+    e.enc_both(
+        brnz.bind(B1),
+        rec_t8jccb_abcd.opcodes(&JUMP_SHORT_IF_NOT_EQUAL),
+    );
+    e.enc_both(brnz.bind(B1), rec_t8jccd_abcd.opcodes(&TEST_REG));
 
     // Jump tables.
     e.enc64(
         jump_table_entry.bind(I64),
-        rec_jt_entry.opcodes(vec![0x63]).rex().w(),
+        rec_jt_entry.opcodes(&MOVSXD).rex().w(),
     );
-    e.enc32(jump_table_entry.bind(I32), rec_jt_entry.opcodes(vec![0x8b]));
+    e.enc32(jump_table_entry.bind(I32), rec_jt_entry.opcodes(&MOV_LOAD));
 
     e.enc64(
         jump_table_base.bind(I64),
-        rec_jt_base.opcodes(vec![0x8d]).rex().w(),
+        rec_jt_base.opcodes(&LEA).rex().w(),
     );
-    e.enc32(jump_table_base.bind(I32), rec_jt_base.opcodes(vec![0x8d]));
+    e.enc32(jump_table_base.bind(I32), rec_jt_base.opcodes(&LEA));
 
     e.enc_x86_64(
         indirect_jump_table_br.bind(I64),
-        rec_indirect_jmp.opcodes(vec![0xff]).rrr(4),
+        rec_indirect_jmp.opcodes(&JUMP_ABSOLUTE).rrr(4),
     );
     e.enc32(
         indirect_jump_table_br.bind(I32),
-        rec_indirect_jmp.opcodes(vec![0xff]).rrr(4),
+        rec_indirect_jmp.opcodes(&JUMP_ABSOLUTE).rrr(4),
     );
 
     // Trap as ud2
-    e.enc32(trap, rec_trap.opcodes(vec![0x0f, 0x0b]));
-    e.enc64(trap, rec_trap.opcodes(vec![0x0f, 0x0b]));
-    e.enc32(resumable_trap, rec_trap.opcodes(vec![0x0f, 0x0b]));
-    e.enc64(resumable_trap, rec_trap.opcodes(vec![0x0f, 0x0b]));
+    e.enc32(trap, rec_trap.opcodes(&UNDEFINED2));
+    e.enc64(trap, rec_trap.opcodes(&UNDEFINED2));
+    e.enc32(resumable_trap, rec_trap.opcodes(&UNDEFINED2));
+    e.enc64(resumable_trap, rec_trap.opcodes(&UNDEFINED2));
 
     // Debug trap as int3
     e.enc32_rec(debugtrap, rec_debugtrap, 0);
     e.enc64_rec(debugtrap, rec_debugtrap, 0);
 
     e.enc32_rec(trapif, rec_trapif, 0);
     e.enc64_rec(trapif, rec_trapif, 0);
     e.enc32_rec(trapff, rec_trapff, 0);
     e.enc64_rec(trapff, rec_trapff, 0);
 
     // Comparisons
-    e.enc_i32_i64(icmp, rec_icscc.opcodes(vec![0x39]));
-    e.enc_i32_i64(icmp_imm, rec_icscc_ib.opcodes(vec![0x83]).rrr(7));
-    e.enc_i32_i64(icmp_imm, rec_icscc_id.opcodes(vec![0x81]).rrr(7));
-    e.enc_i32_i64(ifcmp, rec_rcmp.opcodes(vec![0x39]));
-    e.enc_i32_i64(ifcmp_imm, rec_rcmp_ib.opcodes(vec![0x83]).rrr(7));
-    e.enc_i32_i64(ifcmp_imm, rec_rcmp_id.opcodes(vec![0x81]).rrr(7));
+    e.enc_i32_i64(icmp, rec_icscc.opcodes(&CMP_REG));
+    e.enc_i32_i64(icmp_imm, rec_icscc_ib.opcodes(&CMP_IMM8).rrr(7));
+    e.enc_i32_i64(icmp_imm, rec_icscc_id.opcodes(&CMP_IMM).rrr(7));
+    e.enc_i32_i64(ifcmp, rec_rcmp.opcodes(&CMP_REG));
+    e.enc_i32_i64(ifcmp_imm, rec_rcmp_ib.opcodes(&CMP_IMM8).rrr(7));
+    e.enc_i32_i64(ifcmp_imm, rec_rcmp_id.opcodes(&CMP_IMM).rrr(7));
     // TODO: We could special-case ifcmp_imm(x, 0) to TEST(x, x).
 
-    e.enc32(ifcmp_sp.bind(I32), rec_rcmp_sp.opcodes(vec![0x39]));
-    e.enc64(
-        ifcmp_sp.bind(I64),
-        rec_rcmp_sp.opcodes(vec![0x39]).rex().w(),
-    );
+    e.enc32(ifcmp_sp.bind(I32), rec_rcmp_sp.opcodes(&CMP_REG));
+    e.enc64(ifcmp_sp.bind(I64), rec_rcmp_sp.opcodes(&CMP_REG).rex().w());
 
     // Convert flags to bool.
     // This encodes `b1` as an 8-bit low register with the value 0 or 1.
-    e.enc_both(trueif, rec_seti_abcd.opcodes(vec![0x0f, 0x90]));
-    e.enc_both(trueff, rec_setf_abcd.opcodes(vec![0x0f, 0x90]));
+    e.enc_both(trueif, rec_seti_abcd.opcodes(&SET_BYTE_IF_OVERFLOW));
+    e.enc_both(trueff, rec_setf_abcd.opcodes(&SET_BYTE_IF_OVERFLOW));
 
     // Conditional move (a.k.a integer select).
-    e.enc_i32_i64(selectif, rec_cmov.opcodes(vec![0x0f, 0x40]));
+    e.enc_i32_i64(selectif, rec_cmov.opcodes(&CMOV_OVERFLOW));
 
     // Bit scan forwards and reverse
-    e.enc_i32_i64(x86_bsf, rec_bsf_and_bsr.opcodes(vec![0x0f, 0xbc]));
-    e.enc_i32_i64(x86_bsr, rec_bsf_and_bsr.opcodes(vec![0x0f, 0xbd]));
+    e.enc_i32_i64(x86_bsf, rec_bsf_and_bsr.opcodes(&BIT_SCAN_FORWARD));
+    e.enc_i32_i64(x86_bsr, rec_bsf_and_bsr.opcodes(&BIT_SCAN_REVERSE));
 
     // Convert bool to int.
     //
     // This assumes that b1 is represented as an 8-bit low register with the value 0
     // or 1.
     //
     // Encode movzbq as movzbl, because it's equivalent and shorter.
     e.enc32(
         bint.bind(I32).bind(B1),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
 
     e.enc64(
         bint.bind(I64).bind(B1),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb6]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_BYTE).rex(),
     );
     e.enc64(
         bint.bind(I64).bind(B1),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
     e.enc64(
         bint.bind(I32).bind(B1),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb6]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_BYTE).rex(),
     );
     e.enc64(
         bint.bind(I32).bind(B1),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
 
     // Numerical conversions.
 
     // Reducing an integer is a no-op.
     e.enc32_rec(ireduce.bind(I8).bind(I16), rec_null, 0);
     e.enc32_rec(ireduce.bind(I8).bind(I32), rec_null, 0);
     e.enc32_rec(ireduce.bind(I16).bind(I32), rec_null, 0);
@@ -1512,373 +1464,356 @@ pub(crate) fn define(
     e.enc64_rec(ireduce.bind(I32).bind(I64), rec_null, 0);
 
     // TODO: Add encodings for cbw, cwde, cdqe, which are sign-extending
     // instructions for %al/%ax/%eax to %ax/%eax/%rax.
 
     // movsbl
     e.enc32(
         sextend.bind(I32).bind(I8),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xbe]),
+        rec_urm_noflags_abcd.opcodes(&MOVSX_BYTE),
     );
     e.enc64(
         sextend.bind(I32).bind(I8),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbe]).rex(),
+        rec_urm_noflags.opcodes(&MOVSX_BYTE).rex(),
     );
     e.enc64(
         sextend.bind(I32).bind(I8),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xbe]),
+        rec_urm_noflags_abcd.opcodes(&MOVSX_BYTE),
     );
 
     // movswl
     e.enc32(
         sextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbf]),
+        rec_urm_noflags.opcodes(&MOVSX_WORD),
     );
     e.enc64(
         sextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbf]).rex(),
+        rec_urm_noflags.opcodes(&MOVSX_WORD).rex(),
     );
     e.enc64(
         sextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbf]),
+        rec_urm_noflags.opcodes(&MOVSX_WORD),
     );
 
     // movsbq
     e.enc64(
         sextend.bind(I64).bind(I8),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbe]).rex().w(),
+        rec_urm_noflags.opcodes(&MOVSX_BYTE).rex().w(),
     );
 
     // movswq
     e.enc64(
         sextend.bind(I64).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xbf]).rex().w(),
+        rec_urm_noflags.opcodes(&MOVSX_WORD).rex().w(),
     );
 
     // movslq
     e.enc64(
         sextend.bind(I64).bind(I32),
-        rec_urm_noflags.opcodes(vec![0x63]).rex().w(),
+        rec_urm_noflags.opcodes(&MOVSXD).rex().w(),
     );
 
     // movzbl
     e.enc32(
         uextend.bind(I32).bind(I8),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
     e.enc64(
         uextend.bind(I32).bind(I8),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb6]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_BYTE).rex(),
     );
     e.enc64(
         uextend.bind(I32).bind(I8),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
 
     // movzwl
     e.enc32(
         uextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb7]),
+        rec_urm_noflags.opcodes(&MOVZX_WORD),
     );
     e.enc64(
         uextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb7]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_WORD).rex(),
     );
     e.enc64(
         uextend.bind(I32).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb7]),
+        rec_urm_noflags.opcodes(&MOVZX_WORD),
     );
 
     // movzbq, encoded as movzbl because it's equivalent and shorter.
     e.enc64(
         uextend.bind(I64).bind(I8),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb6]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_BYTE).rex(),
     );
     e.enc64(
         uextend.bind(I64).bind(I8),
-        rec_urm_noflags_abcd.opcodes(vec![0x0f, 0xb6]),
+        rec_urm_noflags_abcd.opcodes(&MOVZX_BYTE),
     );
 
     // movzwq, encoded as movzwl because it's equivalent and shorter
     e.enc64(
         uextend.bind(I64).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb7]).rex(),
+        rec_urm_noflags.opcodes(&MOVZX_WORD).rex(),
     );
     e.enc64(
         uextend.bind(I64).bind(I16),
-        rec_urm_noflags.opcodes(vec![0x0f, 0xb7]),
+        rec_urm_noflags.opcodes(&MOVZX_WORD),
     );
 
     // A 32-bit register copy clears the high 32 bits.
     e.enc64(
         uextend.bind(I64).bind(I32),
-        rec_umr.opcodes(vec![0x89]).rex(),
+        rec_umr.opcodes(&MOV_STORE).rex(),
     );
-    e.enc64(uextend.bind(I64).bind(I32), rec_umr.opcodes(vec![0x89]));
+    e.enc64(uextend.bind(I64).bind(I32), rec_umr.opcodes(&MOV_STORE));
 
     // Floating point
 
     // Floating-point constants equal to 0.0 can be encoded using either `xorps` or `xorpd`, for
     // 32-bit and 64-bit floats respectively.
     let f_unary_ieee32 = formats.get(formats.by_name("UnaryIeee32"));
     let is_zero_32_bit_float = InstructionPredicate::new_is_zero_32bit_float(f_unary_ieee32, "imm");
     e.enc32_instp(
         f32const,
-        rec_f32imm_z.opcodes(vec![0x0f, 0x57]),
+        rec_f32imm_z.opcodes(&XORPS),
         is_zero_32_bit_float.clone(),
     );
 
     let f_unary_ieee64 = formats.get(formats.by_name("UnaryIeee64"));
     let is_zero_64_bit_float = InstructionPredicate::new_is_zero_64bit_float(f_unary_ieee64, "imm");
     e.enc32_instp(
         f64const,
-        rec_f64imm_z.opcodes(vec![0x66, 0x0f, 0x57]),
+        rec_f64imm_z.opcodes(&XORPD),
         is_zero_64_bit_float.clone(),
     );
 
-    e.enc_x86_64_instp(
-        f32const,
-        rec_f32imm_z.opcodes(vec![0x0f, 0x57]),
-        is_zero_32_bit_float,
-    );
-    e.enc_x86_64_instp(
-        f64const,
-        rec_f64imm_z.opcodes(vec![0x66, 0x0f, 0x57]),
-        is_zero_64_bit_float,
-    );
+    e.enc_x86_64_instp(f32const, rec_f32imm_z.opcodes(&XORPS), is_zero_32_bit_float);
+    e.enc_x86_64_instp(f64const, rec_f64imm_z.opcodes(&XORPD), is_zero_64_bit_float);
 
     // movd
     e.enc_both(
         bitcast.bind(F32).bind(I32),
-        rec_frurm.opcodes(vec![0x66, 0x0f, 0x6e]),
+        rec_frurm.opcodes(&MOVD_LOAD_XMM),
     );
     e.enc_both(
         bitcast.bind(I32).bind(F32),
-        rec_rfumr.opcodes(vec![0x66, 0x0f, 0x7e]),
+        rec_rfumr.opcodes(&MOVD_STORE_XMM),
     );
 
     // movq
     e.enc64(
         bitcast.bind(F64).bind(I64),
-        rec_frurm.opcodes(vec![0x66, 0x0f, 0x6e]).rex().w(),
+        rec_frurm.opcodes(&MOVD_LOAD_XMM).rex().w(),
     );
     e.enc64(
         bitcast.bind(I64).bind(F64),
-        rec_rfumr.opcodes(vec![0x66, 0x0f, 0x7e]).rex().w(),
+        rec_rfumr.opcodes(&MOVD_STORE_XMM).rex().w(),
     );
 
     // movaps
-    e.enc_both(copy.bind(F32), rec_furm.opcodes(vec![0x0f, 0x28]));
-    e.enc_both(copy.bind(F64), rec_furm.opcodes(vec![0x0f, 0x28]));
-
-    // TODO For x86-64, only define REX forms for now, since we can't describe the special regunit
-    // immediate operands with the current constraint language.
-    e.enc32(regmove.bind(F32), rec_frmov.opcodes(vec![0x0f, 0x28]));
-    e.enc64(regmove.bind(F32), rec_frmov.opcodes(vec![0x0f, 0x28]).rex());
+    e.enc_both(copy.bind(F32), rec_furm.opcodes(&MOVAPS_LOAD));
+    e.enc_both(copy.bind(F64), rec_furm.opcodes(&MOVAPS_LOAD));
 
     // TODO For x86-64, only define REX forms for now, since we can't describe the special regunit
     // immediate operands with the current constraint language.
-    e.enc32(regmove.bind(F64), rec_frmov.opcodes(vec![0x0f, 0x28]));
-    e.enc64(regmove.bind(F64), rec_frmov.opcodes(vec![0x0f, 0x28]).rex());
+    e.enc32(regmove.bind(F32), rec_frmov.opcodes(&MOVAPS_LOAD));
+    e.enc64(regmove.bind(F32), rec_frmov.opcodes(&MOVAPS_LOAD).rex());
+
+    // TODO For x86-64, only define REX forms for now, since we can't describe the special regunit
+    // immediate operands with the current constraint language.
+    e.enc32(regmove.bind(F64), rec_frmov.opcodes(&MOVAPS_LOAD));
+    e.enc64(regmove.bind(F64), rec_frmov.opcodes(&MOVAPS_LOAD).rex());
 
     // cvtsi2ss
-    e.enc_i32_i64(
-        fcvt_from_sint.bind(F32),
-        rec_frurm.opcodes(vec![0xf3, 0x0f, 0x2a]),
-    );
+    e.enc_i32_i64(fcvt_from_sint.bind(F32), rec_frurm.opcodes(&CVTSI2SS));
 
     // cvtsi2sd
-    e.enc_i32_i64(
-        fcvt_from_sint.bind(F64),
-        rec_frurm.opcodes(vec![0xf2, 0x0f, 0x2a]),
-    );
+    e.enc_i32_i64(fcvt_from_sint.bind(F64), rec_frurm.opcodes(&CVTSI2SD));
 
     // cvtss2sd
-    e.enc_both(
-        fpromote.bind(F64).bind(F32),
-        rec_furm.opcodes(vec![0xf3, 0x0f, 0x5a]),
-    );
+    e.enc_both(fpromote.bind(F64).bind(F32), rec_furm.opcodes(&CVTSS2SD));
 
     // cvtsd2ss
-    e.enc_both(
-        fdemote.bind(F32).bind(F64),
-        rec_furm.opcodes(vec![0xf2, 0x0f, 0x5a]),
-    );
+    e.enc_both(fdemote.bind(F32).bind(F64), rec_furm.opcodes(&CVTSD2SS));
 
     // cvttss2si
     e.enc_both(
         x86_cvtt2si.bind(I32).bind(F32),
-        rec_rfurm.opcodes(vec![0xf3, 0x0f, 0x2c]),
+        rec_rfurm.opcodes(&CVTTSS2SI),
     );
     e.enc64(
         x86_cvtt2si.bind(I64).bind(F32),
-        rec_rfurm.opcodes(vec![0xf3, 0x0f, 0x2c]).rex().w(),
+        rec_rfurm.opcodes(&CVTTSS2SI).rex().w(),
     );
 
     // cvttsd2si
     e.enc_both(
         x86_cvtt2si.bind(I32).bind(F64),
-        rec_rfurm.opcodes(vec![0xf2, 0x0f, 0x2c]),
+        rec_rfurm.opcodes(&CVTTSD2SI),
     );
     e.enc64(
         x86_cvtt2si.bind(I64).bind(F64),
-        rec_rfurm.opcodes(vec![0xf2, 0x0f, 0x2c]).rex().w(),
+        rec_rfurm.opcodes(&CVTTSD2SI).rex().w(),
     );
 
     // Exact square roots.
-    e.enc_both(sqrt.bind(F32), rec_furm.opcodes(vec![0xf3, 0x0f, 0x51]));
-    e.enc_both(sqrt.bind(F64), rec_furm.opcodes(vec![0xf2, 0x0f, 0x51]));
+    e.enc_both(sqrt.bind(F32), rec_furm.opcodes(&SQRTSS));
+    e.enc_both(sqrt.bind(F64), rec_furm.opcodes(&SQRTSD));
 
     // Rounding. The recipe looks at the opcode to pick an immediate.
     for inst in &[nearest, floor, ceil, trunc] {
-        e.enc_both_isap(
-            inst.bind(F32),
-            rec_furmi_rnd.opcodes(vec![0x66, 0x0f, 0x3a, 0x0a]),
-            use_sse41,
-        );
-        e.enc_both_isap(
-            inst.bind(F64),
-            rec_furmi_rnd.opcodes(vec![0x66, 0x0f, 0x3a, 0x0b]),
-            use_sse41,
-        );
+        e.enc_both_isap(inst.bind(F32), rec_furmi_rnd.opcodes(&ROUNDSS), use_sse41);
+        e.enc_both_isap(inst.bind(F64), rec_furmi_rnd.opcodes(&ROUNDSD), use_sse41);
     }
 
     // Binary arithmetic ops.
-    for &(inst, opc) in &[
-        (fadd, 0x58),
-        (fsub, 0x5c),
-        (fmul, 0x59),
-        (fdiv, 0x5e),
-        (x86_fmin, 0x5d),
-        (x86_fmax, 0x5f),
-    ] {
-        e.enc_both(inst.bind(F32), rec_fa.opcodes(vec![0xf3, 0x0f, opc]));
-        e.enc_both(inst.bind(F64), rec_fa.opcodes(vec![0xf2, 0x0f, opc]));
-    }
+    e.enc_both(fadd.bind(F32), rec_fa.opcodes(&ADDSS));
+    e.enc_both(fadd.bind(F64), rec_fa.opcodes(&ADDSD));
+
+    e.enc_both(fsub.bind(F32), rec_fa.opcodes(&SUBSS));
+    e.enc_both(fsub.bind(F64), rec_fa.opcodes(&SUBSD));
+
+    e.enc_both(fmul.bind(F32), rec_fa.opcodes(&MULSS));
+    e.enc_both(fmul.bind(F64), rec_fa.opcodes(&MULSD));
+
+    e.enc_both(fdiv.bind(F32), rec_fa.opcodes(&DIVSS));
+    e.enc_both(fdiv.bind(F64), rec_fa.opcodes(&DIVSD));
+
+    e.enc_both(x86_fmin.bind(F32), rec_fa.opcodes(&MINSS));
+    e.enc_both(x86_fmin.bind(F64), rec_fa.opcodes(&MINSD));
+
+    e.enc_both(x86_fmax.bind(F32), rec_fa.opcodes(&MAXSS));
+    e.enc_both(x86_fmax.bind(F64), rec_fa.opcodes(&MAXSD));
 
     // Binary bitwise ops.
-    for &(inst, opc) in &[(band, 0x54), (bor, 0x56), (bxor, 0x57)] {
-        e.enc_both(inst.bind(F32), rec_fa.opcodes(vec![0x0f, opc]));
-        e.enc_both(inst.bind(F64), rec_fa.opcodes(vec![0x0f, opc]));
-    }
+    //
+    // The F64 version is intentionally encoded using the single-precision opcode:
+    // the operation is identical and the encoding is one byte shorter.
+    e.enc_both(band.bind(F32), rec_fa.opcodes(&ANDPS));
+    e.enc_both(band.bind(F64), rec_fa.opcodes(&ANDPS));
+
+    e.enc_both(bor.bind(F32), rec_fa.opcodes(&ORPS));
+    e.enc_both(bor.bind(F64), rec_fa.opcodes(&ORPS));
+
+    e.enc_both(bxor.bind(F32), rec_fa.opcodes(&XORPS));
+    e.enc_both(bxor.bind(F64), rec_fa.opcodes(&XORPS));
 
     // The `andnps(x,y)` instruction computes `~x&y`, while band_not(x,y)` is `x&~y.
-    e.enc_both(band_not.bind(F32), rec_fax.opcodes(vec![0x0f, 0x55]));
-    e.enc_both(band_not.bind(F64), rec_fax.opcodes(vec![0x0f, 0x55]));
+    e.enc_both(band_not.bind(F32), rec_fax.opcodes(&ANDNPS));
+    e.enc_both(band_not.bind(F64), rec_fax.opcodes(&ANDNPS));
 
     // Comparisons.
     //
     // This only covers the condition codes in `supported_floatccs`, the rest are
     // handled by legalization patterns.
-    e.enc_both(fcmp.bind(F32), rec_fcscc.opcodes(vec![0x0f, 0x2e]));
-    e.enc_both(fcmp.bind(F64), rec_fcscc.opcodes(vec![0x66, 0x0f, 0x2e]));
-    e.enc_both(ffcmp.bind(F32), rec_fcmp.opcodes(vec![0x0f, 0x2e]));
-    e.enc_both(ffcmp.bind(F64), rec_fcmp.opcodes(vec![0x66, 0x0f, 0x2e]));
+    e.enc_both(fcmp.bind(F32), rec_fcscc.opcodes(&UCOMISS));
+    e.enc_both(fcmp.bind(F64), rec_fcscc.opcodes(&UCOMISD));
+    e.enc_both(ffcmp.bind(F32), rec_fcmp.opcodes(&UCOMISS));
+    e.enc_both(ffcmp.bind(F64), rec_fcmp.opcodes(&UCOMISD));
 
     // SIMD vector size: eventually multiple vector sizes may be supported but for now only
     // SSE-sized vectors are available.
     let sse_vector_size: u64 = 128;
 
     // SIMD splat: before x86 can use vector data, it must be moved to XMM registers; see
     // legalize.rs for how this is done; once there, x86_pshuf* (below) is used for broadcasting the
     // value across the register.
 
     let allowed_simd_type = |t: &LaneType| t.lane_bits() >= 8 && t.lane_bits() < 128;
 
     // PSHUFB, 8-bit shuffle using two XMM registers.
-    for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 8) {
+    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
         let instruction = x86_pshufb.bind_vector_from_lane(ty, sse_vector_size);
-        let template = rec_fa.nonrex().opcodes(vec![0x66, 0x0f, 0x38, 00]);
+        let template = rec_fa.nonrex().opcodes(&PSHUFB);
         e.enc32_isap(instruction.clone(), template.clone(), use_ssse3_simd);
         e.enc64_isap(instruction, template, use_ssse3_simd);
     }
 
     // PSHUFD, 32-bit shuffle using one XMM register and a u8 immediate.
     for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 32) {
         let instruction = x86_pshufd.bind_vector_from_lane(ty, sse_vector_size);
-        let template = rec_r_ib_unsigned_fpr
-            .nonrex()
-            .opcodes(vec![0x66, 0x0f, 0x70]);
+        let template = rec_r_ib_unsigned_fpr.nonrex().opcodes(&PSHUFD);
         e.enc32(instruction.clone(), template.clone());
         e.enc64(instruction, template);
     }
 
     // SIMD scalar_to_vector; this uses MOV to copy the scalar value to an XMM register; according
     // to the Intel manual: "When the destination operand is an XMM register, the source operand is
-    // written to the low doubleword of the register and the regiser is zero-extended to 128 bits."
+    // written to the low doubleword of the register and the register is zero-extended to 128 bits."
     for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
         let instruction = scalar_to_vector.bind_vector_from_lane(ty, sse_vector_size);
         if ty.is_float() {
             e.enc_32_64_rec(instruction, rec_null_fpr, 0);
         } else {
-            let template = rec_frurm.opcodes(vec![0x66, 0x0f, 0x6e]); // MOVD/MOVQ
+            let template = rec_frurm.opcodes(&MOVD_LOAD_XMM);
             if ty.lane_bits() < 64 {
                 // no 32-bit encodings for 64-bit widths
                 e.enc32(instruction.clone(), template.clone());
             }
             e.enc_x86_64(instruction, template);
         }
     }
 
     // SIMD insertlane
-    let mut x86_pinsr_mapping: HashMap<u64, (Vec<u8>, Option<SettingPredicateNumber>)> =
+    let mut x86_pinsr_mapping: HashMap<u64, (&'static [u8], Option<SettingPredicateNumber>)> =
         HashMap::new();
-    x86_pinsr_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x20], Some(use_sse41_simd))); // PINSRB
-    x86_pinsr_mapping.insert(16, (vec![0x66, 0x0f, 0xc4], None)); // PINSRW from SSE2
-    x86_pinsr_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRD
-    x86_pinsr_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRQ, only x86_64
+    x86_pinsr_mapping.insert(8, (&PINSRB, Some(use_sse41_simd)));
+    x86_pinsr_mapping.insert(16, (&PINSRW, None));
+    x86_pinsr_mapping.insert(32, (&PINSR, Some(use_sse41_simd)));
+    x86_pinsr_mapping.insert(64, (&PINSR, Some(use_sse41_simd)));
 
     for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
         if let Some((opcode, isap)) = x86_pinsr_mapping.get(&ty.lane_bits()) {
             let instruction = x86_pinsr.bind_vector_from_lane(ty, sse_vector_size);
-            let template = rec_r_ib_unsigned_r.opcodes(opcode.clone());
+            let template = rec_r_ib_unsigned_r.opcodes(opcode);
             if ty.lane_bits() < 64 {
                 e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone());
             } else {
                 // It turns out the 64-bit widths have REX/W encodings and only are available on
                 // x86_64.
                 e.enc64_maybe_isap(instruction, template.rex().w(), isap.clone());
             }
         }
     }
 
     // For legalizing insertlane with floats, INSERTPS from SSE4.1.
     {
         let instruction = x86_insertps.bind_vector_from_lane(F32, sse_vector_size);
-        let template = rec_fa_ib.nonrex().opcodes(vec![0x66, 0x0f, 0x3a, 0x21]);
+        let template = rec_fa_ib.nonrex().opcodes(&INSERTPS);
         e.enc_32_64_maybe_isap(instruction, template, Some(use_sse41_simd));
     }
 
     // For legalizing insertlane with floats,  MOVSD from SSE2.
     {
         let instruction = x86_movsd.bind_vector_from_lane(F64, sse_vector_size);
-        let template = rec_fa.nonrex().opcodes(vec![0xf2, 0x0f, 0x10]);
+        let template = rec_fa.nonrex().opcodes(&MOVSD_LOAD);
         e.enc_32_64_maybe_isap(instruction, template, None); // from SSE2
     }
 
     // For legalizing insertlane with floats, MOVLHPS from SSE.
     {
         let instruction = x86_movlhps.bind_vector_from_lane(F64, sse_vector_size);
-        let template = rec_fa.nonrex().opcodes(vec![0x0f, 0x16]);
+        let template = rec_fa.nonrex().opcodes(&MOVLHPS);
         e.enc_32_64_maybe_isap(instruction, template, None); // from SSE
     }
 
     // SIMD extractlane
-    let mut x86_pextr_mapping: HashMap<u64, (Vec<u8>, Option<SettingPredicateNumber>)> =
+    let mut x86_pextr_mapping: HashMap<u64, (&'static [u8], Option<SettingPredicateNumber>)> =
         HashMap::new();
-    x86_pextr_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x14], Some(use_sse41_simd))); // PEXTRB
-    x86_pextr_mapping.insert(16, (vec![0x66, 0x0f, 0xc5], None)); // PEXTRW from SSE2, SSE4.1 has a PEXTRW that can move to reg/m16 but the opcode is four bytes
-    x86_pextr_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRD
-    x86_pextr_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRQ, only x86_64
+    x86_pextr_mapping.insert(8, (&PEXTRB, Some(use_sse41_simd)));
+    x86_pextr_mapping.insert(16, (&PEXTRW_SSE2, None));
+    x86_pextr_mapping.insert(32, (&PEXTR, Some(use_sse41_simd)));
+    x86_pextr_mapping.insert(64, (&PEXTR, Some(use_sse41_simd)));
 
     for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
         if let Some((opcode, isap)) = x86_pextr_mapping.get(&ty.lane_bits()) {
             let instruction = x86_pextr.bind_vector_from_lane(ty, sse_vector_size);
-            let template = rec_r_ib_unsigned_gpr.opcodes(opcode.clone());
+            let template = rec_r_ib_unsigned_gpr.opcodes(opcode);
             if ty.lane_bits() < 64 {
                 e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone());
             } else {
                 // It turns out the 64-bit widths have REX/W encodings and only are available on
                 // x86_64.
                 e.enc64_maybe_isap(instruction, template.rex().w(), isap.clone());
             }
         }
@@ -1912,37 +1847,137 @@ pub(crate) fn define(
                     .bind(*float_type)
                     .bind_vector_from_lane(lane_type, sse_vector_size),
                 rec_null_fpr,
                 0,
             );
         }
     }
 
+    // SIMD vconst for special cases (all zeroes, all ones)
+    // this must be encoded prior to the MOVUPS implementation (below) so the compiler sees this
+    // encoding first
+    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
+        let f_unary_const = formats.get(formats.by_name("UnaryConst"));
+        let instruction = vconst.bind_vector_from_lane(ty, sse_vector_size);
+
+        let is_zero_128bit =
+            InstructionPredicate::new_is_all_zeroes_128bit(f_unary_const, "constant_handle");
+        let template = rec_vconst_optimized.nonrex().opcodes(&PXOR);
+        e.enc_32_64_func(instruction.clone(), template, |builder| {
+            builder.inst_predicate(is_zero_128bit)
+        });
+
+        let is_ones_128bit =
+            InstructionPredicate::new_is_all_ones_128bit(f_unary_const, "constant_handle");
+        let template = rec_vconst_optimized.nonrex().opcodes(&PCMPEQB);
+        e.enc_32_64_func(instruction, template, |builder| {
+            builder.inst_predicate(is_ones_128bit)
+        });
+    }
+
     // SIMD vconst using MOVUPS
     // TODO it would be ideal if eventually this became the more efficient MOVAPS but we would have
     // to guarantee that the constants are aligned when emitted and there is currently no mechanism
     // for that; alternately, constants could be loaded into XMM registers using a sequence like:
     // MOVQ + MOVHPD + MOVQ + MOVLPD (this allows the constants to be immediates instead of stored
     // in memory) but some performance measurements are needed.
     for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
         let instruction = vconst.bind_vector_from_lane(ty, sse_vector_size);
-        let template = rec_vconst.nonrex().opcodes(vec![0x0f, 0x10]);
+        let template = rec_vconst.nonrex().opcodes(&MOVUPS_LOAD);
+        e.enc_32_64_maybe_isap(instruction, template, None); // from SSE
+    }
+
+    // SIMD bor using ORPS
+    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
+        let instruction = bor.bind_vector_from_lane(ty, sse_vector_size);
+        let template = rec_fa.nonrex().opcodes(&ORPS);
         e.enc_32_64_maybe_isap(instruction, template, None); // from SSE
     }
 
+    // SIMD register movement: store, load, spill, fill, regmove. All of these use encodings of
+    // MOVUPS and MOVAPS from SSE (TODO ideally all of these would either use MOVAPS when we have
+    // alignment or type-specific encodings, see https://github.com/CraneStation/cranelift/issues/1039).
+    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
+        // Store
+        let bound_store = store.bind_vector_from_lane(ty, sse_vector_size).bind_any();
+        e.enc_32_64(bound_store.clone(), rec_fst.opcodes(&MOVUPS_STORE));
+        e.enc_32_64(bound_store.clone(), rec_fstDisp8.opcodes(&MOVUPS_STORE));
+        e.enc_32_64(bound_store, rec_fstDisp32.opcodes(&MOVUPS_STORE));
+
+        // Load
+        let bound_load = load.bind_vector_from_lane(ty, sse_vector_size).bind_any();
+        e.enc_32_64(bound_load.clone(), rec_fld.opcodes(&MOVUPS_LOAD));
+        e.enc_32_64(bound_load.clone(), rec_fldDisp8.opcodes(&MOVUPS_LOAD));
+        e.enc_32_64(bound_load, rec_fldDisp32.opcodes(&MOVUPS_LOAD));
+
+        // Spill
+        let bound_spill = spill.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_spill, rec_fspillSib32.opcodes(&MOVUPS_STORE));
+        let bound_regspill = regspill.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_regspill, rec_fregspill32.opcodes(&MOVUPS_STORE));
+
+        // Fill
+        let bound_fill = fill.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_fill, rec_ffillSib32.opcodes(&MOVUPS_LOAD));
+        let bound_regfill = regfill.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_regfill, rec_fregfill32.opcodes(&MOVUPS_LOAD));
+        let bound_fill_nop = fill_nop.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64_rec(bound_fill_nop, rec_ffillnull, 0);
+
+        // Regmove
+        let bound_regmove = regmove.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_regmove, rec_frmov.opcodes(&MOVAPS_LOAD));
+
+        // Copy
+        let bound_copy = copy.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64(bound_copy, rec_furm.opcodes(&MOVAPS_LOAD));
+        let bound_copy_nop = copy_nop.bind_vector_from_lane(ty, sse_vector_size);
+        e.enc_32_64_rec(bound_copy_nop, rec_stacknull, 0);
+    }
+
+    // SIMD integer addition
+    for (ty, opcodes) in &[(I8, &PADDB), (I16, &PADDW), (I32, &PADDD), (I64, &PADDQ)] {
+        let iadd = iadd.bind_vector_from_lane(ty.clone(), sse_vector_size);
+        e.enc_32_64(iadd, rec_fa.opcodes(*opcodes));
+    }
+
+    // SIMD icmp using PCMPEQ*
+    let mut pcmpeq_mapping: HashMap<u64, (&[u8], Option<SettingPredicateNumber>)> = HashMap::new();
+    pcmpeq_mapping.insert(8, (&PCMPEQB, None));
+    pcmpeq_mapping.insert(16, (&PCMPEQW, None));
+    pcmpeq_mapping.insert(32, (&PCMPEQD, None));
+    pcmpeq_mapping.insert(64, (&PCMPEQQ, Some(use_sse41_simd)));
+    for ty in ValueType::all_lane_types().filter(|t| t.is_int() && allowed_simd_type(t)) {
+        if let Some((opcodes, isa_predicate)) = pcmpeq_mapping.get(&ty.lane_bits()) {
+            let instruction = icmp.bind_vector_from_lane(ty, sse_vector_size);
+            let f_int_compare = formats.get(formats.by_name("IntCompare"));
+            let has_eq_condition_code =
+                InstructionPredicate::new_has_condition_code(f_int_compare, IntCC::Equal, "cond");
+            let template = rec_icscc_fpr.nonrex().opcodes(*opcodes);
+            e.enc_32_64_func(instruction, template, |builder| {
+                let builder = builder.inst_predicate(has_eq_condition_code);
+                if let Some(p) = isa_predicate {
+                    builder.isa_predicate(*p)
+                } else {
+                    builder
+                }
+            });
+        }
+    }
+
     // Reference type instructions
 
     // Null references implemented as iconst 0.
-    e.enc32(null.bind_ref(R32), rec_pu_id_ref.opcodes(vec![0xb8]));
+    e.enc32(null.bind_ref(R32), rec_pu_id_ref.opcodes(&MOV_IMM));
 
-    e.enc64(null.bind_ref(R64), rec_pu_id_ref.rex().opcodes(vec![0xb8]));
-    e.enc64(null.bind_ref(R64), rec_pu_id_ref.opcodes(vec![0xb8]));
+    e.enc64(null.bind_ref(R64), rec_pu_id_ref.rex().opcodes(&MOV_IMM));
+    e.enc64(null.bind_ref(R64), rec_pu_id_ref.opcodes(&MOV_IMM));
 
     // is_null, implemented by testing whether the value is 0.
-    e.enc_r32_r64_rex_only(is_null, rec_is_zero.opcodes(vec![0x85]));
+    e.enc_r32_r64_rex_only(is_null, rec_is_zero.opcodes(&TEST_REG));
 
     // safepoint instruction calls sink, no actual encoding.
     e.enc32_rec(safepoint, rec_safepoint, 0);
     e.enc64_rec(safepoint, rec_safepoint, 0);
 
     e
 }
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/legalize.rs
@@ -40,16 +40,17 @@ pub(crate) fn define(shared: &mut Shared
     let isub = insts.by_name("isub");
     let popcnt = insts.by_name("popcnt");
     let raw_bitcast = insts.by_name("raw_bitcast");
     let scalar_to_vector = insts.by_name("scalar_to_vector");
     let sdiv = insts.by_name("sdiv");
     let selectif = insts.by_name("selectif");
     let smulhi = insts.by_name("smulhi");
     let splat = insts.by_name("splat");
+    let shuffle = insts.by_name("shuffle");
     let srem = insts.by_name("srem");
     let udiv = insts.by_name("udiv");
     let umulhi = insts.by_name("umulhi");
     let ushr_imm = insts.by_name("ushr_imm");
     let urem = insts.by_name("urem");
 
     let x86_bsf = x86_instructions.by_name("x86_bsf");
     let x86_bsr = x86_instructions.by_name("x86_bsr");
@@ -323,16 +324,17 @@ pub(crate) fn define(shared: &mut Shared
         let splat_any8x16 = splat.bind_vector_from_lane(ty, sse_vector_size);
         let bitcast_f64_to_any8x16 = raw_bitcast
             .bind_vector_from_lane(ty, sse_vector_size)
             .bind(F64);
         narrow.legalize(
             def!(y = splat_any8x16(x)),
             vec![
                 def!(a = scalar_to_vector(x)), // move into the lowest 8 bits of an XMM register
+                // TODO replace the following two instructions with `vconst(0)` when this is possible; see https://github.com/CraneStation/cranelift/issues/1052
                 def!(b = f64const(ieee64_zero)), // zero out a different XMM register; the shuffle mask for moving the lowest byte to all other byte lanes is 0x0
                 def!(c = bitcast_f64_to_any8x16(b)), // no instruction emitted; informs the SSA that the 0 in b can be used as a vector of this type
                 def!(y = x86_pshufb(a, c)), // PSHUFB takes two XMM operands, one of which is a shuffle mask (i.e. b)
             ],
         );
     }
 
     // SIMD splat: 16-bits
@@ -375,13 +377,14 @@ pub(crate) fn define(shared: &mut Shared
             def!(y = splat_any64x2(x)),
             vec![
                 def!(a = scalar_to_vector(x)), // move into the lowest 64 bits of an XMM register
                 def!(y = insertlane(a, uimm8_one, x)), // move into the highest 64 bits of the same XMM register
             ],
         );
     }
 
+    narrow.custom_legalize(shuffle, "convert_shuffle");
     narrow.custom_legalize(extractlane, "convert_extractlane");
     narrow.custom_legalize(insertlane, "convert_insertlane");
 
     narrow.build_and_add_to(&mut shared.transform_groups);
 }
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs
@@ -4,16 +4,17 @@ use crate::cdsl::isa::TargetIsa;
 use crate::shared::types::Bool::B1;
 use crate::shared::types::Float::{F32, F64};
 use crate::shared::types::Int::{I16, I32, I64, I8};
 use crate::shared::Definitions as SharedDefinitions;
 
 mod encodings;
 mod instructions;
 mod legalize;
+mod opcodes;
 mod recipes;
 mod registers;
 mod settings;
 
 pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
     let settings = settings::define(&shared_defs.settings);
     let regs = registers::define();
 
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/opcodes.rs
@@ -0,0 +1,377 @@
+//! Static, named definitions of instruction opcodes.
+
+/// Empty opcode for use as a default.
+pub static EMPTY: [u8; 0] = [];
+
+/// Add with carry flag r{16,32,64} to r/m of the same size.
+pub static ADC: [u8; 1] = [0x11];
+
+/// Add r{16,32,64} to r/m of the same size.
+pub static ADD: [u8; 1] = [0x01];
+
+/// Add imm{16,32} to r/m{16,32,64}, possibly sign-extended.
+pub static ADD_IMM: [u8; 1] = [0x81];
+
+/// Add sign-extended imm8 to r/m{16,32,64}.
+pub static ADD_IMM8_SIGN_EXTEND: [u8; 1] = [0x83];
+
+/// Add the low double-precision floating-point value from xmm2/mem to xmm1
+/// and store the result in xmm1.
+pub static ADDSD: [u8; 3] = [0xf2, 0x0f, 0x58];
+
+/// Add the low single-precision floating-point value from xmm2/mem to xmm1
+/// and store the result in xmm1.
+pub static ADDSS: [u8; 3] = [0xf3, 0x0f, 0x58];
+
+/// r/m{16,32,64} AND register of the same size (Intel docs have a typo).
+pub static AND: [u8; 1] = [0x21];
+
+/// imm{16,32} AND r/m{16,32,64}, possibly sign-extended.
+pub static AND_IMM: [u8; 1] = [0x81];
+
+/// r/m{16,32,64} AND sign-extended imm8.
+pub static AND_IMM8_SIGN_EXTEND: [u8; 1] = [0x83];
+
+/// Return the bitwise logical AND NOT of packed single-precision floating-point
+/// values in xmm1 and xmm2/mem.
+pub static ANDNPS: [u8; 2] = [0x0f, 0x55];
+
+/// Return the bitwise logical AND of packed single-precision floating-point values
+/// in xmm1 and xmm2/mem.
+pub static ANDPS: [u8; 2] = [0x0f, 0x54];
+
+/// Bit scan forward (stores index of first encountered 1 from the front).
+pub static BIT_SCAN_FORWARD: [u8; 2] = [0x0f, 0xbc];
+
+/// Bit scan reverse (stores index of first encountered 1 from the back).
+pub static BIT_SCAN_REVERSE: [u8; 2] = [0x0f, 0xbd];
+
+/// Call near, relative, displacement relative to next instruction (sign-extended).
+pub static CALL_RELATIVE: [u8; 1] = [0xe8];
+
+/// Move r/m{16,32,64} if overflow (OF=1).
+pub static CMOV_OVERFLOW: [u8; 2] = [0x0f, 0x40];
+
+/// Compare imm{16,32} with r/m{16,32,64} (sign-extended if 64).
+pub static CMP_IMM: [u8; 1] = [0x81];
+
+/// Compare imm8 with r/m{16,32,64}.
+pub static CMP_IMM8: [u8; 1] = [0x83];
+
+/// Compare r{16,32,64} with r/m of the same size.
+pub static CMP_REG: [u8; 1] = [0x39];
+
+/// Convert scalar double-precision floating-point value to scalar single-precision
+/// floating-point value.
+pub static CVTSD2SS: [u8; 3] = [0xf2, 0x0f, 0x5a];
+
+/// Convert doubleword integer to scalar double-precision floating-point value.
+pub static CVTSI2SD: [u8; 3] = [0xf2, 0x0f, 0x2a];
+
+/// Convert doubleword integer to scalar single-precision floating-point value.
+pub static CVTSI2SS: [u8; 3] = [0xf3, 0x0f, 0x2a];
+
+/// Convert scalar single-precision floating-point value to scalar double-precision
+/// float-point value.
+pub static CVTSS2SD: [u8; 3] = [0xf3, 0x0f, 0x5a];
+
+/// Convert with truncation scalar double-precision floating-point value to signed
+/// integer.
+pub static CVTTSD2SI: [u8; 3] = [0xf2, 0x0f, 0x2c];
+
+/// Convert with truncation scalar single-precision floating-point value to integer.
+pub static CVTTSS2SI: [u8; 3] = [0xf3, 0x0f, 0x2c];
+
+/// Unsigned divide for {16,32,64}-bit.
+pub static DIV: [u8; 1] = [0xf7];
+
+/// Divide low double-precision floating-point value in xmm1 by low double-precision
+/// floating-point value in xmm2/m64.
+pub static DIVSD: [u8; 3] = [0xf2, 0x0f, 0x5e];
+
+/// Divide low single-precision floating-point value in xmm1 by low single-precision
+/// floating-point value in xmm2/m32.
+pub static DIVSS: [u8; 3] = [0xf3, 0x0f, 0x5e];
+
+/// Signed divide for {16,32,64}-bit.
+pub static IDIV: [u8; 1] = [0xf7];
+
+/// Signed multiply for {16,32,64}-bit, generic registers.
+pub static IMUL: [u8; 2] = [0x0f, 0xaf];
+
+/// Signed multiply for {16,32,64}-bit, storing into RDX:RAX.
+pub static IMUL_RDX_RAX: [u8; 1] = [0xf7];
+
+/// Insert scalar single-precision floating-point value.
+pub static INSERTPS: [u8; 4] = [0x66, 0x0f, 0x3a, 0x21];
+
+/// Either:
+///  1. Jump near, absolute indirect, RIP = 64-bit offset from register or memory.
+///  2. Jump far, absolute indirect, address given in m16:64.
+pub static JUMP_ABSOLUTE: [u8; 1] = [0xff];
+
+/// Jump near, relative, RIP = RIP + 32-bit displacement sign extended to 64 bits.
+pub static JUMP_NEAR_RELATIVE: [u8; 1] = [0xe9];
+
+/// Jump near (rel32) if overflow (OF=1).
+pub static JUMP_NEAR_IF_OVERFLOW: [u8; 2] = [0x0f, 0x80];
+
+/// Jump short, relative, RIP = RIP + 8-bit displacement sign extended to 64 bits.
+pub static JUMP_SHORT: [u8; 1] = [0xeb];
+
+/// Jump short (rel8) if equal (ZF=1).
+pub static JUMP_SHORT_IF_EQUAL: [u8; 1] = [0x74];
+
+/// Jump short (rel8) if not equal (ZF=0).
+pub static JUMP_SHORT_IF_NOT_EQUAL: [u8; 1] = [0x75];
+
+/// Jump short (rel8) if overflow (OF=1).
+pub static JUMP_SHORT_IF_OVERFLOW: [u8; 1] = [0x70];
+
+/// Store effective address for m in register r{16,32,64}.
+pub static LEA: [u8; 1] = [0x8d];
+
+/// Count the number of leading zero bits.
+pub static LZCNT: [u8; 3] = [0xf3, 0x0f, 0xbd];
+
+/// Return the maximum scalar double-precision floating-point value between
+/// xmm2/m64 and xmm1.
+pub static MAXSD: [u8; 3] = [0xf2, 0x0f, 0x5f];
+
+/// Return the maximum scalar single-precision floating-point value between
+/// xmm2/m32 and xmm1.
+pub static MAXSS: [u8; 3] = [0xf3, 0x0f, 0x5f];
+
+/// Return the minimum scalar double-precision floating-point value between
+/// xmm2/m64 and xmm1.
+pub static MINSD: [u8; 3] = [0xf2, 0x0f, 0x5d];
+
+/// Return the minimum scalar single-precision floating-point value between
+/// xmm2/m32 and xmm1.
+pub static MINSS: [u8; 3] = [0xf3, 0x0f, 0x5d];
+
+/// Move r8 to r/m8.
+pub static MOV_BYTE_STORE: [u8; 1] = [0x88];
+
+/// Move imm{16,32,64} to same-sized register.
+pub static MOV_IMM: [u8; 1] = [0xb8];
+
+/// Move imm{16,32} to r{16,32,64}, sign-extended if 64-bit target.
+pub static MOV_IMM_SIGNEXTEND: [u8; 1] = [0xc7];
+
+/// Move {r/m16, r/m32, r/m64} to same-sized register.
+pub static MOV_LOAD: [u8; 1] = [0x8b];
+
+/// Move r16 to r/m16.
+pub static MOV_STORE_16: [u8; 2] = [0x66, 0x89];
+
+/// Move {r16, r32, r64} to same-sized register or memory.
+pub static MOV_STORE: [u8; 1] = [0x89];
+
+/// Move aligned packed single-precision floating-point values from x/m to xmm (SSE).
+pub static MOVAPS_LOAD: [u8; 2] = [0x0f, 0x28];
+
+/// Move doubleword from r/m32 to xmm (SSE2). Quadword with REX prefix.
+pub static MOVD_LOAD_XMM: [u8; 3] = [0x66, 0x0f, 0x6e];
+
+/// Move doubleword from xmm to r/m32 (SSE2). Quadword with REX prefix.
+pub static MOVD_STORE_XMM: [u8; 3] = [0x66, 0x0f, 0x7e];
+
+/// Move packed single-precision floating-point values low to high (SSE).
+pub static MOVLHPS: [u8; 2] = [0x0f, 0x16];
+
+/// Move scalar double-precision floating-point value (from reg/mem to reg).
+pub static MOVSD_LOAD: [u8; 3] = [0xf2, 0x0f, 0x10];
+
+/// Move scalar double-precision floating-point value (from reg to reg/mem).
+pub static MOVSD_STORE: [u8; 3] = [0xf2, 0x0f, 0x11];
+
+/// Move scalar single-precision floating-point value (from reg to reg/mem).
+pub static MOVSS_STORE: [u8; 3] = [0xf3, 0x0f, 0x11];
+
+/// Move scalar single-precision floating-point-value (from reg/mem to reg).
+pub static MOVSS_LOAD: [u8; 3] = [0xf3, 0x0f, 0x10];
+
+/// Move byte to register with sign-extension.
+pub static MOVSX_BYTE: [u8; 2] = [0x0f, 0xbe];
+
+/// Move word to register with sign-extension.
+pub static MOVSX_WORD: [u8; 2] = [0x0f, 0xbf];
+
+/// Move doubleword to register with sign-extension.
+pub static MOVSXD: [u8; 1] = [0x63];
+
+/// Move unaligned packed single-precision floating-point from x/m to xmm (SSE).
+pub static MOVUPS_LOAD: [u8; 2] = [0x0f, 0x10];
+
+/// Move unaligned packed single-precision floating-point value from xmm to x/m (SSE).
+pub static MOVUPS_STORE: [u8; 2] = [0x0f, 0x11];
+
+/// Move byte to register with zero-extension.
+pub static MOVZX_BYTE: [u8; 2] = [0x0f, 0xb6];
+
+/// Move word to register with zero-extension.
+pub static MOVZX_WORD: [u8; 2] = [0x0f, 0xb7];
+
+/// Unsigned multiply for {16,32,64}-bit.
+pub static MUL: [u8; 1] = [0xf7];
+
+/// Multiply the low double-precision floating-point value in xmm2/m64 by the
+/// low double-precision floating-point value in xmm1.
+pub static MULSD: [u8; 3] = [0xf2, 0x0f, 0x59];
+
+/// Multiply the low single-precision floating-point value in xmm2/m32 by the
+/// low single-precision floating-point value in xmm1.
+pub static MULSS: [u8; 3] = [0xf3, 0x0f, 0x59];
+
+/// Reverse each bit of r/m{16,32,64}.
+pub static NOT: [u8; 1] = [0xf7];
+
+/// r{16,32,64} OR register of same size.
+pub static OR: [u8; 1] = [0x09];
+
+/// imm{16,32} OR r/m{16,32,64}, possibly sign-extended.
+pub static OR_IMM: [u8; 1] = [0x81];
+
+/// r/m{16,32,64} OR sign-extended imm8.
+pub static OR_IMM8_SIGN_EXTEND: [u8; 1] = [0x83];
+
+/// Return the bitwise logical OR of packed single-precision values in xmm and x/m (SSE).
+pub static ORPS: [u8; 2] = [0x0f, 0x56];
+
+/// Add packed byte integers from xmm2/m128 and xmm1 (SSE2).
+pub static PADDB: [u8; 3] = [0x66, 0x0f, 0xfc];
+
+/// Add packed doubleword integers from xmm2/m128 and xmm1 (SSE2).
+pub static PADDD: [u8; 3] = [0x66, 0x0f, 0xfe];
+
+/// Add packed quadword integers from xmm2/m128 and xmm1 (SSE2).
+pub static PADDQ: [u8; 3] = [0x66, 0x0f, 0xd4];
+
+/// Add packed word integers from xmm2/m128 and xmm1 (SSE2).
+pub static PADDW: [u8; 3] = [0x66, 0x0f, 0xfd];
+
+/// Compare packed data for equal (SSE2).
+pub static PCMPEQB: [u8; 3] = [0x66, 0x0f, 0x74];
+
+/// Compare packed data for equal (SSE2).
+pub static PCMPEQD: [u8; 3] = [0x66, 0x0f, 0x76];
+
+/// Compare packed data for equal (SSE4.1).
+pub static PCMPEQQ: [u8; 4] = [0x66, 0x0f, 0x38, 0x29];
+
+/// Compare packed data for equal (SSE2).
+pub static PCMPEQW: [u8; 3] = [0x66, 0x0f, 0x75];
+
+/// Extract doubleword or quadword, depending on REX.W (SSE4.1).
+pub static PEXTR: [u8; 4] = [0x66, 0x0f, 0x3a, 0x16];
+
+/// Extract byte (SSE4.1).
+pub static PEXTRB: [u8; 4] = [0x66, 0x0f, 0x3a, 0x14];
+
+/// Extract word (SSE2). There is a 4-byte SSE4.1 variant that can also move to m/16.
+pub static PEXTRW_SSE2: [u8; 3] = [0x66, 0x0f, 0xc5];
+
+/// Insert doubleword or quadword, depending on REX.W (SSE4.1).
+pub static PINSR: [u8; 4] = [0x66, 0x0f, 0x3a, 0x22];
+
+/// Insert byte (SSE4.1).
+pub static PINSRB: [u8; 4] = [0x66, 0x0f, 0x3a, 0x20];
+
+/// Insert word (SSE2).
+pub static PINSRW: [u8; 3] = [0x66, 0x0f, 0xc4];
+
+/// Pop top of stack into r{16,32,64}; increment stack pointer.
+pub static POP_REG: [u8; 1] = [0x58];
+
+/// Returns the count of number of bits set to 1.
+pub static POPCNT: [u8; 3] = [0xf3, 0x0f, 0xb8];
+
+/// Shuffle bytes in xmm1 according to contents of xmm2/m128 (SSE3).
+pub static PSHUFB: [u8; 4] = [0x66, 0x0f, 0x38, 0x00];
+
+/// Shuffle the doublewords in xmm2/m128 based on the encoding in imm8 and
+/// store the result in xmm1 (SSE2).
+pub static PSHUFD: [u8; 3] = [0x66, 0x0f, 0x70];
+
+/// Push r{16,32,64}.
+pub static PUSH_REG: [u8; 1] = [0x50];
+
+/// Logical exclusive OR (SSE2).
+pub static PXOR: [u8; 3] = [0x66, 0x0f, 0xef];
+
+/// Near return to calling procedure.
+pub static RET_NEAR: [u8; 1] = [0xc3];
+
+/// General rotation opcode. Kind of rotation depends on encoding.
+pub static ROTATE_CL: [u8; 1] = [0xd3];
+
+/// General rotation opcode. Kind of rotation depends on encoding.
+pub static ROTATE_IMM8: [u8; 1] = [0xc1];
+
+/// Round scalar doubl-precision floating-point values.
+pub static ROUNDSD: [u8; 4] = [0x66, 0x0f, 0x3a, 0x0b];
+
+/// Round scalar single-precision floating-point values.
+pub static ROUNDSS: [u8; 4] = [0x66, 0x0f, 0x3a, 0x0a];
+
+/// Subtract with borrow r{16,32,64} from r/m of the same size.
+pub static SBB: [u8; 1] = [0x19];
+
+/// Set byte if overflow (OF=1).
+pub static SET_BYTE_IF_OVERFLOW: [u8; 2] = [0x0f, 0x90];
+
+/// Compute square root of scalar double-precision floating-point value.
+pub static SQRTSD: [u8; 3] = [0xf2, 0x0f, 0x51];
+
+/// Compute square root of scalar single-precision value.
+pub static SQRTSS: [u8; 3] = [0xf3, 0x0f, 0x51];
+
+/// Subtract r{16,32,64} from r/m of same size.
+pub static SUB: [u8; 1] = [0x29];
+
+/// Subtract the low double-precision floating-point value in xmm2/m64 from xmm1
+/// and store the result in xmm1.
+pub static SUBSD: [u8; 3] = [0xf2, 0x0f, 0x5c];
+
+/// Subtract the low single-precision floating-point value in xmm2/m32 from xmm1
+/// and store the result in xmm1.
+pub static SUBSS: [u8; 3] = [0xf3, 0x0f, 0x5c];
+
+/// AND r8 with r/m8; set SF, ZF, PF according to result.
+pub static TEST_BYTE_REG: [u8; 1] = [0x84];
+
+/// AND {r16, r32, r64} with r/m of the same size; set SF, ZF, PF according to result.
+pub static TEST_REG: [u8; 1] = [0x85];
+
+/// Count the number of trailing zero bits.
+pub static TZCNT: [u8; 3] = [0xf3, 0x0f, 0xbc];
+
+/// Compare low double-precision floating-point values in xmm1 and xmm2/mem64
+/// and set the EFLAGS flags accordingly.
+pub static UCOMISD: [u8; 3] = [0x66, 0x0f, 0x2e];
+
+/// Compare low single-precision floating-point values in xmm1 and xmm2/mem32
+/// and set the EFLAGS flags accordingly.
+pub static UCOMISS: [u8; 2] = [0x0f, 0x2e];
+
+/// Raise invalid opcode instruction.
+pub static UNDEFINED2: [u8; 2] = [0x0f, 0x0b];
+
+/// imm{16,32} XOR r/m{16,32,64}, possibly sign-extended.
+pub static XOR_IMM: [u8; 1] = [0x81];
+
+/// r/m{16,32,64} XOR sign-extended imm8.
+pub static XOR_IMM8_SIGN_EXTEND: [u8; 1] = [0x83];
+
+/// r/m{16,32,64} XOR register of the same size.
+pub static XOR: [u8; 1] = [0x31];
+
+/// r/m8 XOR r8.
+pub static XORB: [u8; 1] = [0x30];
+
+/// Bitwise logical XOR of packed double-precision floating-point values.
+pub static XORPD: [u8; 3] = [0x66, 0x0f, 0x57];
+
+/// Bitwise logical XOR of packed single-precision floating-point values.
+pub static XORPS: [u8; 2] = [0x0f, 0x57];
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs
@@ -5,20 +5,22 @@ use crate::cdsl::formats::{FormatRegistr
 use crate::cdsl::instructions::InstructionPredicate;
 use crate::cdsl::recipes::{
     EncodingRecipe, EncodingRecipeBuilder, OperandConstraint, Register, Stack,
 };
 use crate::cdsl::regs::IsaRegs;
 use crate::cdsl::settings::SettingGroup;
 use crate::shared::Definitions as SharedDefinitions;
 
+use crate::isa::x86::opcodes;
+
 /// Helper data structure to create recipes and template recipes.
 /// It contains all the recipes and recipe templates that might be used in the encodings crate of
 /// this same directory.
-pub struct RecipeGroup<'builder> {
+pub(crate) struct RecipeGroup<'builder> {
     /// Memoized format pointer, to pass it to builders later.
     formats: &'builder FormatRegistry,
 
     /// Memoized registers description, to pass it to builders later.
     regs: &'builder IsaRegs,
 
     /// All the recipes explicitly created in this file. This is different from the final set of
     /// recipes, which is definitive only once encodings have generated new recipes on the fly.
@@ -181,17 +183,17 @@ pub struct Template<'builder> {
     // Specialized parameters.
     /// Should we include the REX prefix?
     rex: bool,
     /// Value of the W bit (0 or 1).
     w_bit: u16,
     /// Value of the RRR bits (between 0 and 0b111).
     rrr_bits: u16,
     /// Opcode bytes.
-    op_bytes: Vec<u8>,
+    op_bytes: &'static [u8],
 }
 
 impl<'builder> Template<'builder> {
     fn new(
         recipe: EncodingRecipeBuilder,
         formats: &'builder FormatRegistry,
         regs: &'builder IsaRegs,
     ) -> Self {
@@ -199,17 +201,17 @@ impl<'builder> Template<'builder> {
             formats,
             regs,
             recipe,
             requires_prefix: false,
             when_prefixed: None,
             rex: false,
             w_bit: 0,
             rrr_bits: 0,
-            op_bytes: Vec::new(),
+            op_bytes: &opcodes::EMPTY,
         }
     }
 
     fn name(&self) -> &str {
         &self.recipe.name
     }
     fn requires_prefix(self, value: bool) -> Self {
         Self {
@@ -221,17 +223,17 @@ impl<'builder> Template<'builder> {
         assert!(self.when_prefixed.is_none());
         Self {
             when_prefixed: Some(template),
             ..self
         }
     }
 
     // Copy setters.
-    pub fn opcodes(&self, op_bytes: Vec<u8>) -> Self {
+    pub fn opcodes(&self, op_bytes: &'static [u8]) -> Self {
         assert!(!op_bytes.is_empty());
         let mut copy = self.clone();
         copy.op_bytes = op_bytes;
         copy
     }
     pub fn w(&self) -> Self {
         let mut copy = self.clone();
         copy.w_bit = 1;
@@ -391,21 +393,21 @@ pub(crate) fn define<'shared>(
     let f_reg_spill = formats.by_name("RegSpill");
     let f_stack_load = formats.by_name("StackLoad");
     let f_store = formats.by_name("Store");
     let f_store_complex = formats.by_name("StoreComplex");
     let f_ternary = formats.by_name("Ternary");
     let f_trap = formats.by_name("Trap");
     let f_unary = formats.by_name("Unary");
     let f_unary_bool = formats.by_name("UnaryBool");
+    let f_unary_const = formats.by_name("UnaryConst");
     let f_unary_global_value = formats.by_name("UnaryGlobalValue");
     let f_unary_ieee32 = formats.by_name("UnaryIeee32");
     let f_unary_ieee64 = formats.by_name("UnaryIeee64");
     let f_unary_imm = formats.by_name("UnaryImm");
-    let f_unary_imm128 = formats.by_name("UnaryImm128");
 
     // Predicates shorthands.
     let use_sse41 = settings.predicate_by_name("use_sse41");
 
     // Definitions.
     let mut recipes = RecipeGroup::new(formats, regs);
 
     // A null unary instruction that takes a GPR register. Can be used for identity copies and
@@ -2432,24 +2434,36 @@ pub(crate) fn define<'shared>(
                         modrm_sib(out_reg0, sink);
                         sib(imm.trailing_zeros() as u8, in_reg0, in_reg1, sink);
                     }
                 "#,
             ),
     );
 
     recipes.add_template_recipe(
-        EncodingRecipeBuilder::new("vconst", f_unary_imm128, 5)
+        EncodingRecipeBuilder::new("vconst", f_unary_const, 5)
             .operands_out(vec![fpr])
             .clobbers_flags(false)
             .emit(
                 r#"
                     {{PUT_OP}}(bits, rex2(0, out_reg0), sink);
                     modrm_riprel(out_reg0, sink);
-                    const_disp4(imm, func, sink);
+                    const_disp4(constant_handle, func, sink);
+                "#,
+            ),
+    );
+
+    recipes.add_template_recipe(
+        EncodingRecipeBuilder::new("vconst_optimized", f_unary_const, 1)
+            .operands_out(vec![fpr])
+            .clobbers_flags(false)
+            .emit(
+                r#"
+                    {{PUT_OP}}(bits, rex2(out_reg0, out_reg0), sink);
+                    modrm_rr(out_reg0, out_reg0, sink);
                 "#,
             ),
     );
 
     recipes.add_template_recipe(
         EncodingRecipeBuilder::new("jt_base", f_branch_table_base, 5)
             .operands_out(vec![gpr])
             .clobbers_flags(false)
@@ -2903,36 +2917,37 @@ pub(crate) fn define<'shared>(
             .operands_in(vec![gpr, gpr])
             .operands_out(vec![abcd])
             .emit(
                 r#"
                     // Comparison instruction.
                     {{PUT_OP}}(bits, rex2(in_reg0, in_reg1), sink);
                     modrm_rr(in_reg0, in_reg1, sink);
                     // `setCC` instruction, no REX.
-                    use crate::ir::condcodes::IntCC::*;
-                    let setcc = match cond {
-                        Equal => 0x94,
-                        NotEqual => 0x95,
-                        SignedLessThan => 0x9c,
-                        SignedGreaterThanOrEqual => 0x9d,
-                        SignedGreaterThan => 0x9f,
-                        SignedLessThanOrEqual => 0x9e,
-                        UnsignedLessThan => 0x92,
-                        UnsignedGreaterThanOrEqual => 0x93,
-                        UnsignedGreaterThan => 0x97,
-                        UnsignedLessThanOrEqual => 0x96,
-                    };
+                    let setcc = 0x90 | icc2opc(cond);
                     sink.put1(0x0f);
-                    sink.put1(setcc);
+                    sink.put1(setcc as u8);
                     modrm_rr(out_reg0, 0, sink);
                 "#,
             ),
     );
 
+    recipes.add_template_recipe(
+        EncodingRecipeBuilder::new("icscc_fpr", f_int_compare, 1)
+            .operands_in(vec![fpr, fpr])
+            .operands_out(vec![0])
+            .emit(
+                r#"
+                    // Comparison instruction.
+                    {{PUT_OP}}(bits, rex2(in_reg1, in_reg0), sink);
+                    modrm_rr(in_reg1, in_reg0, sink);
+                "#,
+            ),
+    );
+
     {
         let format = formats.get(f_int_compare_imm);
 
         let is_small_imm = InstructionPredicate::new_is_signed_int(format, "imm", 8, 0);
 
         recipes.add_template_recipe(
             EncodingRecipeBuilder::new("icscc_ib", f_int_compare_imm, 2 + 3)
                 .operands_in(vec![gpr])
@@ -2941,31 +2956,19 @@ pub(crate) fn define<'shared>(
                 .emit(
                     r#"
                         // Comparison instruction.
                         {{PUT_OP}}(bits, rex1(in_reg0), sink);
                         modrm_r_bits(in_reg0, bits, sink);
                         let imm: i64 = imm.into();
                         sink.put1(imm as u8);
                         // `setCC` instruction, no REX.
-                        use crate::ir::condcodes::IntCC::*;
-                        let setcc = match cond {
-                            Equal => 0x94,
-                            NotEqual => 0x95,
-                            SignedLessThan => 0x9c,
-                            SignedGreaterThanOrEqual => 0x9d,
-                            SignedGreaterThan => 0x9f,
-                            SignedLessThanOrEqual => 0x9e,
-                            UnsignedLessThan => 0x92,
-                            UnsignedGreaterThanOrEqual => 0x93,
-                            UnsignedGreaterThan => 0x97,
-                            UnsignedLessThanOrEqual => 0x96,
-                        };
+                        let setcc = 0x90 | icc2opc(cond);
                         sink.put1(0x0f);
-                        sink.put1(setcc);
+                        sink.put1(setcc as u8);
                         modrm_rr(out_reg0, 0, sink);
                     "#,
                 ),
         );
 
         let is_big_imm = InstructionPredicate::new_is_signed_int(format, "imm", 32, 0);
 
         recipes.add_template_recipe(
@@ -2976,31 +2979,19 @@ pub(crate) fn define<'shared>(
                 .emit(
                     r#"
                         // Comparison instruction.
                         {{PUT_OP}}(bits, rex1(in_reg0), sink);
                         modrm_r_bits(in_reg0, bits, sink);
                         let imm: i64 = imm.into();
                         sink.put4(imm as u32);
                         // `setCC` instruction, no REX.
-                        use crate::ir::condcodes::IntCC::*;
-                        let setcc = match cond {
-                            Equal => 0x94,
-                            NotEqual => 0x95,
-                            SignedLessThan => 0x9c,
-                            SignedGreaterThanOrEqual => 0x9d,
-                            SignedGreaterThan => 0x9f,
-                            SignedLessThanOrEqual => 0x9e,
-                            UnsignedLessThan => 0x92,
-                            UnsignedGreaterThanOrEqual => 0x93,
-                            UnsignedGreaterThan => 0x97,
-                            UnsignedLessThanOrEqual => 0x96,
-                        };
+                        let setcc = 0x90 | icc2opc(cond);
                         sink.put1(0x0f);
-                        sink.put1(setcc);
+                        sink.put1(setcc as u8);
                         modrm_rr(out_reg0, 0, sink);
                     "#,
                 ),
         );
     }
 
     // Make a FloatCompare instruction predicate with the supported condition codes.
     //
--- a/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs
@@ -1,20 +1,20 @@
 use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder as Builder};
 use crate::shared::{entities::EntityRefs, immediates::Immediates};
 
 pub(crate) fn define(imm: &Immediates, entities: &EntityRefs) -> FormatRegistry {
     let mut registry = FormatRegistry::new();
 
     registry.insert(Builder::new("Unary").value());
     registry.insert(Builder::new("UnaryImm").imm(&imm.imm64));
-    registry.insert(Builder::new("UnaryImm128").imm(&imm.uimm128));
     registry.insert(Builder::new("UnaryIeee32").imm(&imm.ieee32));
     registry.insert(Builder::new("UnaryIeee64").imm(&imm.ieee64));
     registry.insert(Builder::new("UnaryBool").imm(&imm.boolean));
+    registry.insert(Builder::new("UnaryConst").imm(&imm.pool_constant));
     registry.insert(Builder::new("UnaryGlobalValue").imm(&entities.global_value));
 
     registry.insert(Builder::new("Binary").value().value());
     registry.insert(Builder::new("BinaryImm").value().imm(&imm.imm64));
 
     // The select instructions are controlled by the second VALUE operand.
     // The first VALUE operand is the controlling flag which has a derived type.
     // The fma instruction has the same constraint on all inputs.
@@ -38,33 +38,39 @@ pub(crate) fn define(imm: &Immediates, e
             .imm_with_name("lane", &imm.uimm8)
             .value(),
     );
     registry.insert(
         Builder::new("ExtractLane")
             .value()
             .imm_with_name("lane", &imm.uimm8),
     );
+    registry.insert(
+        Builder::new("Shuffle")
+            .value()
+            .value()
+            .imm_with_name("mask", &imm.uimm128),
+    );
 
     registry.insert(Builder::new("IntCompare").imm(&imm.intcc).value().value());
     registry.insert(
         Builder::new("IntCompareImm")
             .imm(&imm.intcc)
             .value()
             .imm(&imm.imm64),
     );
     registry.insert(Builder::new("IntCond").imm(&imm.intcc).value());
 
     registry.insert(
         Builder::new("FloatCompare")
             .imm(&imm.floatcc)
             .value()
             .value(),
     );
-    registry.insert(Builder::new("FloatCond").imm(&imm.floatcc).value());;
+    registry.insert(Builder::new("FloatCond").imm(&imm.floatcc).value());
 
     registry.insert(
         Builder::new("IntSelect")
             .imm(&imm.intcc)
             .value()
             .value()
             .value(),
     );
--- a/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs
@@ -18,16 +18,22 @@ pub(crate) struct Immediates {
     pub uimm32: OperandKind,
 
     /// An unsigned 128-bit immediate integer operand.
     ///
     /// This operand is used to pass entire 128-bit vectors as immediates to instructions like
     /// const.
     pub uimm128: OperandKind,
 
+    /// A constant stored in the constant pool.
+    ///
+    /// This operand is used to pass constants to instructions like vconst while storing the
+    /// actual bytes in the constant pool.
+    pub pool_constant: OperandKind,
+
     /// A 32-bit immediate signed offset.
     ///
     /// This is used to represent an immediate address offset in load/store instructions.
     pub offset32: OperandKind,
 
     /// A 32-bit immediate floating point operand.
     ///
     /// IEEE 754-2008 binary32 interchange format.
@@ -79,16 +85,22 @@ impl Immediates {
                 .build(),
 
             uimm32: Builder::new_imm("uimm32")
                 .doc("A 32-bit immediate unsigned integer.")
                 .build(),
 
             uimm128: Builder::new_imm("uimm128")
                 .doc("A 128-bit immediate unsigned integer.")
+                .rust_type("ir::Immediate")
+                .build(),
+
+            pool_constant: Builder::new_imm("poolConstant")
+                .doc("A constant stored in the constant pool.")
+                .default_member("constant_handle")
                 .rust_type("ir::Constant")
                 .build(),
 
             offset32: Builder::new_imm("offset32")
                 .doc("A 32-bit immediate signed offset.")
                 .default_member("offset")
                 .build(),
 
@@ -112,16 +124,18 @@ impl Immediates {
                 intcc_values.insert("sge", "SignedGreaterThanOrEqual");
                 intcc_values.insert("sgt", "SignedGreaterThan");
                 intcc_values.insert("sle", "SignedLessThanOrEqual");
                 intcc_values.insert("slt", "SignedLessThan");
                 intcc_values.insert("uge", "UnsignedGreaterThanOrEqual");
                 intcc_values.insert("ugt", "UnsignedGreaterThan");
                 intcc_values.insert("ule", "UnsignedLessThanOrEqual");
                 intcc_values.insert("ult", "UnsignedLessThan");
+                intcc_values.insert("of", "Overflow");
+                intcc_values.insert("nof", "NotOverflow");
                 Builder::new_enum("intcc", intcc_values)
                     .doc("An integer comparison condition code.")
                     .default_member("cond")
                     .rust_type("ir::condcodes::IntCC")
                     .build()
             },
 
             floatcc: {
--- a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
@@ -1085,17 +1085,17 @@ pub(crate) fn define(
         "#,
         )
         .operands_in(vec![N])
         .operands_out(vec![a]),
     );
 
     let N = &operand_doc(
         "N",
-        &imm.uimm128,
+        &imm.pool_constant,
         "The 16 immediate bytes of a 128-bit vector",
     );
     let a = &operand_doc("a", TxN, "A constant vector value");
 
     ig.push(
         Inst::new(
             "vconst",
             r#"
@@ -1103,16 +1103,51 @@ pub(crate) fn define(
 
         Construct a vector with the given immediate bytes.
         "#,
         )
         .operands_in(vec![N])
         .operands_out(vec![a]),
     );
 
+    let mask = &operand_doc(
+        "mask",
+        &imm.uimm128,
+        "The 16 immediate bytes used for selecting the elements to shuffle",
+    );
+    let Tx16 = &TypeVar::new(
+        "Tx16",
+        "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \
+         lane counts and widths",
+        TypeSetBuilder::new()
+            .ints(8..8)
+            .bools(8..8)
+            .simd_lanes(16..16)
+            .includes_scalars(false)
+            .build(),
+    );
+    let a = &operand_doc("a", Tx16, "A vector value");
+    let b = &operand_doc("b", Tx16, "A vector value");
+
+    ig.push(
+        Inst::new(
+            "shuffle",
+            r#"
+        SIMD vector shuffle.
+        
+        Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the
+        immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of 
+        16-31 selects the (i-16)th element of the second vector. Immediate values outside of the 
+        0-31 range place a 0 in the resulting vector lane.
+        "#,
+        )
+        .operands_in(vec![a, b, mask])
+        .operands_out(vec![a]),
+    );
+
     let a = &operand_doc("a", Ref, "A constant reference null value");
 
     ig.push(
         Inst::new(
             "null",
             r#"
         Null constant value for reference types.
 
@@ -1546,16 +1581,18 @@ pub(crate) fn define(
         .operands_out(vec![a]),
     );
 
     let a = &operand("a", &Int.as_bool());
     let Cond = &operand("Cond", &imm.intcc);
     let x = &operand("x", Int);
     let y = &operand("y", Int);
 
+    // TODO(ryzokuken): Add documentation for unsigned overflow.
+    // TODO(ryzokuken): Add documentation for signed overflow.
     ig.push(
         Inst::new(
             "icmp",
             r#"
         Integer comparison.
 
         The condition code determines if the operands are interpreted as signed
         or unsigned integers.
--- a/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/legalize.rs
@@ -59,17 +59,16 @@ pub(crate) fn define(insts: &Instruction
     let cls = insts.by_name("cls");
     let clz = insts.by_name("clz");
     let ctz = insts.by_name("ctz");
     let fabs = insts.by_name("fabs");
     let f32const = insts.by_name("f32const");
     let f64const = insts.by_name("f64const");
     let fcopysign = insts.by_name("fcopysign");
     let fcvt_from_sint = insts.by_name("fcvt_from_sint");
-    let fcvt_from_uint = insts.by_name("fcvt_from_uint");
     let fneg = insts.by_name("fneg");
     let iadd = insts.by_name("iadd");
     let iadd_cin = insts.by_name("iadd_cin");
     let iadd_cout = insts.by_name("iadd_cout");
     let iadd_carry = insts.by_name("iadd_carry");
     let iadd_ifcin = insts.by_name("iadd_ifcin");
     let iadd_ifcout = insts.by_name("iadd_ifcout");
     let iadd_imm = insts.by_name("iadd_imm");
@@ -89,16 +88,17 @@ pub(crate) fn define(insts: &Instruction
     let istore8 = insts.by_name("istore8");
     let istore16 = insts.by_name("istore16");
     let isub = insts.by_name("isub");
     let isub_bin = insts.by_name("isub_bin");
     let isub_bout = insts.by_name("isub_bout");
     let isub_borrow = insts.by_name("isub_borrow");
     let isub_ifbin = insts.by_name("isub_ifbin");
     let isub_ifbout = insts.by_name("isub_ifbout");
+    let jump = insts.by_name("jump");
     let load = insts.by_name("load");
     let popcnt = insts.by_name("popcnt");
     let rotl = insts.by_name("rotl");
     let rotl_imm = insts.by_name("rotl_imm");
     let rotr = insts.by_name("rotr");
     let rotr_imm = insts.by_name("rotr_imm");
     let sdiv = insts.by_name("sdiv");
     let sdiv_imm = insts.by_name("sdiv_imm");
@@ -185,16 +185,18 @@ pub(crate) fn define(insts: &Instruction
     let xl = var("xl");
     let xh = var("xh");
     let yl = var("yl");
     let yh = var("yh");
     let al = var("al");
     let ah = var("ah");
     let cc = var("cc");
     let ebb = var("ebb");
+    let ebb1 = var("ebb1");
+    let ebb2 = var("ebb2");
     let ptr = var("ptr");
     let flags = var("flags");
     let offset = var("off");
     let vararg = var("vararg");
 
     narrow.custom_legalize(load, "narrow_load");
     narrow.custom_legalize(store, "narrow_store");
 
@@ -255,21 +257,23 @@ pub(crate) fn define(insts: &Instruction
                 )
             ),
             def!(c = band(a, b)),
             def!(brz(c, ebb, vararg)),
         ],
     );
 
     narrow.legalize(
-        def!(brnz.I128(x, ebb, vararg)),
+        def!(brnz.I128(x, ebb1, vararg)),
         vec![
             def!((xl, xh) = isplit(x)),
-            def!(brnz(xl, ebb, vararg)),
-            def!(brnz(xh, ebb, vararg)),
+            def!(brnz(xl, ebb1, vararg)),
+            def!(jump(ebb2, Literal::empty_vararg())),
+            ebb!(ebb2),
+            def!(brnz(xh, ebb1, vararg)),
         ],
     );
 
     // Widen instructions with one input operand.
     for &op in &[bnot, popcnt] {
         for &int_ty in &[I8, I16] {
             widen.legalize(
                 def!(a = op.int_ty(b)),
@@ -537,31 +541,22 @@ pub(crate) fn define(insts: &Instruction
         vec![
             def!((a1, b1) = isub_bout(x, y)),
             def!(b_int = bint(b_in)),
             def!((a, b2) = isub_bout(a1, b_int)),
             def!(b = bor(b1, b2)),
         ],
     );
 
-    // Expansions for fcvt_from_{u,s}int for smaller integer types.
-    // These use expand and not widen because the controlling type variable for
-    // these instructions are f32/f64, which are legalized as part of the expand
+    // Expansion for fcvt_from_sint for smaller integer types.
+    // This uses expand and not widen because the controlling type variable for
+    // this instruction is f32/f64, which is legalized as part of the expand
     // group.
     for &dest_ty in &[F32, F64] {
         for &src_ty in &[I8, I16] {
-            let bound_inst = fcvt_from_uint.bind(dest_ty).bind(src_ty);
-            expand.legalize(
-                def!(a = bound_inst(b)),
-                vec![
-                    def!(x = uextend.I32(b)),
-                    def!(a = fcvt_from_uint.dest_ty(x)),
-                ],
-            );
-
             let bound_inst = fcvt_from_sint.bind(dest_ty).bind(src_ty);
             expand.legalize(
                 def!(a = bound_inst(b)),
                 vec![
                     def!(x = sextend.I32(b)),
                     def!(a = fcvt_from_sint.dest_ty(x)),
                 ],
             );
--- a/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/mod.rs
@@ -24,17 +24,17 @@ pub(crate) struct Definitions {
     pub format_registry: FormatRegistry,
     pub transform_groups: TransformGroups,
 }
 
 pub(crate) fn define() -> Definitions {
     let mut all_instructions = AllInstructions::new();
 
     let immediates = Immediates::new();
-    let entities = EntityRefs::new();;
+    let entities = EntityRefs::new();
     let format_registry = formats::define(&immediates, &entities);
     let instructions = instructions::define(
         &mut all_instructions,
         &format_registry,
         &immediates,
         &entities,
     );
     let transform_groups = legalize::define(&instructions, &immediates);
--- a/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/settings.rs
@@ -3,21 +3,22 @@ use crate::cdsl::settings::{SettingGroup
 pub fn define() -> SettingGroup {
     let mut settings = SettingGroupBuilder::new("shared");
 
     settings.add_enum(
         "opt_level",
         r#"
         Optimization level:
 
-        - default: Very profitable optimizations enabled, none slow.
-        - best: Enable all optimizations
-        - fastest: Optimize for compile time by disabling most optimizations.
+        - none: Minimise compile time by disabling most optimizations.
+        - speed: Generate the fastest possible code
+        - speed_and_size: like "speed", but also perform transformations
+          aimed at reducing code size.
         "#,
-        vec!["default", "best", "fastest"],
+        vec!["none", "speed", "speed_and_size"],
     );
 
     settings.add_bool(
         "enable_verifier",
         r#"
         Run the Cranelift IR verifier at strategic times during compilation.
 
         This makes compilation slower but catches many bugs. The verifier is
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-shared/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"17643920d895c99deb5b2849b2a9b55ff5cc61877f9c297914b8ba1987bb0731","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"a410bc2f5dcbde499c0cd299c2620bc8111e3c5b3fccdd9e2d85caf3c24fdab3","src/condcodes.rs":"838c9becb7d42ef0eb98e70505b52783a2e900b6532316708466f2157fa807d9","src/lib.rs":"f42e7d8606285e8e2b8994486bdad7e0796abc4778efdf55dbd20e4320a25e62"},"package":null}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-shared/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+authors = ["The Cranelift Project Developers"]
+name = "cranelift-codegen-shared"
+version = "0.44.0"
+description = "For code shared between cranelift-codegen-meta and cranelift-codegen"
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/CraneStation/cranelift"
+readme = "README.md"
+edition = "2018"
+
+[dependencies]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-shared/LICENSE
@@ -0,0 +1,220 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+--- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-shared/README.md
@@ -0,0 +1,2 @@
+This crate contains shared definitions for use in both `cranelift-codegen-meta` and `cranelift
+-codegen`.
rename from third_party/rust/cranelift-codegen/src/ir/condcodes.rs
rename to third_party/rust/cranelift-codegen-shared/src/condcodes.rs
--- a/third_party/rust/cranelift-codegen/src/ir/condcodes.rs
+++ b/third_party/rust/cranelift-codegen-shared/src/condcodes.rs
@@ -46,48 +46,56 @@ pub enum IntCC {
     /// Unsigned `<`.
     UnsignedLessThan,
     /// Unsigned `>=`.
     UnsignedGreaterThanOrEqual,
     /// Unsigned `>`.
     UnsignedGreaterThan,
     /// Unsigned `<=`.
     UnsignedLessThanOrEqual,
+    /// Signed Overflow.
+    Overflow,
+    /// Signed No Overflow.
+    NotOverflow,
 }
 
 impl CondCode for IntCC {
     fn inverse(self) -> Self {
         use self::IntCC::*;
         match self {
             Equal => NotEqual,
             NotEqual => Equal,
             SignedLessThan => SignedGreaterThanOrEqual,
             SignedGreaterThanOrEqual => SignedLessThan,
             SignedGreaterThan => SignedLessThanOrEqual,
             SignedLessThanOrEqual => SignedGreaterThan,
             UnsignedLessThan => UnsignedGreaterThanOrEqual,
             UnsignedGreaterThanOrEqual => UnsignedLessThan,
             UnsignedGreaterThan => UnsignedLessThanOrEqual,
             UnsignedLessThanOrEqual => UnsignedGreaterThan,
+            Overflow => NotOverflow,
+            NotOverflow => Overflow,
         }
     }
 
     fn reverse(self) -> Self {
         use self::IntCC::*;
         match self {
             Equal => Equal,
             NotEqual => NotEqual,
             SignedGreaterThan => SignedLessThan,
             SignedGreaterThanOrEqual => SignedLessThanOrEqual,
             SignedLessThan => SignedGreaterThan,
             SignedLessThanOrEqual => SignedGreaterThanOrEqual,
             UnsignedGreaterThan => UnsignedLessThan,
             UnsignedGreaterThanOrEqual => UnsignedLessThanOrEqual,
             UnsignedLessThan => UnsignedGreaterThan,
             UnsignedLessThanOrEqual => UnsignedGreaterThanOrEqual,
+            Overflow => Overflow,
+            NotOverflow => NotOverflow,
         }
     }
 }
 
 impl Display for IntCC {
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         use self::IntCC::*;
         f.write_str(match *self {
@@ -96,16 +104,18 @@ impl Display for IntCC {
             SignedGreaterThan => "sgt",
             SignedGreaterThanOrEqual => "sge",
             SignedLessThan => "slt",
             SignedLessThanOrEqual => "sle",
             UnsignedGreaterThan => "ugt",
             UnsignedGreaterThanOrEqual => "uge",
             UnsignedLessThan => "ult",
             UnsignedLessThanOrEqual => "ule",
+            Overflow => "of",
+            NotOverflow => "nof",
         })
     }
 }
 
 impl FromStr for IntCC {
     type Err = ();
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -116,16 +126,18 @@ impl FromStr for IntCC {
             "sge" => Ok(SignedGreaterThanOrEqual),
             "sgt" => Ok(SignedGreaterThan),
             "sle" => Ok(SignedLessThanOrEqual),
             "slt" => Ok(SignedLessThan),
             "uge" => Ok(UnsignedGreaterThanOrEqual),
             "ugt" => Ok(UnsignedGreaterThan),
             "ule" => Ok(UnsignedLessThanOrEqual),
             "ult" => Ok(UnsignedLessThan),
+            "of" => Ok(Overflow),
+            "nof" => Ok(NotOverflow),
             _ => Err(()),
         }
     }
 }
 
 /// Condition code for comparing floating point numbers.
 ///
 /// This condition code is used by the `fcmp` instruction to compare floating point values. Two
@@ -265,27 +277,29 @@ impl FromStr for FloatCC {
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use std::string::ToString;
 
-    static INT_ALL: [IntCC; 10] = [
+    static INT_ALL: [IntCC; 12] = [
         IntCC::Equal,
         IntCC::NotEqual,
         IntCC::SignedLessThan,
         IntCC::SignedGreaterThanOrEqual,
         IntCC::SignedGreaterThan,
         IntCC::SignedLessThanOrEqual,
         IntCC::UnsignedLessThan,
         IntCC::UnsignedGreaterThanOrEqual,
         IntCC::UnsignedGreaterThan,
         IntCC::UnsignedLessThanOrEqual,
+        IntCC::Overflow,
+        IntCC::NotOverflow,
     ];
 
     #[test]
     fn int_inverse() {
         for r in &INT_ALL {
             let cc = *r;
             let inv = cc.inverse();
             assert!(cc != inv);
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-shared/src/lib.rs
@@ -0,0 +1,26 @@
+//! This library contains code that is common to both the `cranelift-codegen` and
+//! `cranelift-codegen-meta` libraries.
+
+#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
+#![warn(unused_import_braces)]
+#![cfg_attr(feature = "std", deny(unstable_features))]
+#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
+#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
+#![cfg_attr(
+    feature = "cargo-clippy",
+    warn(
+        clippy::float_arithmetic,
+        clippy::mut_mut,
+        clippy::nonminimal_bool,
+        clippy::option_map_unwrap_or,
+        clippy::option_map_unwrap_or_else,
+        clippy::print_stdout,
+        clippy::unicode_not_nfc,
+        clippy::use_self
+    )
+)]
+
+pub mod condcodes;
+
+/// Version number of this crate.
+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
--- a/third_party/rust/cranelift-codegen/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"99b4b834ec33e1d1917296497e286dad5819fed0600b5ce288a114133efbe734","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"da415b20c563e636bcccaafb43dbdb77d6c48f9c205b16229865abb1afa40964","src/binemit/mod.rs":"90c56d36091646bba7f0ab1b5064d68b8b0c24ece874fcf8c621830b743e9688","src/binemit/relaxation.rs":"7b1082203c688beab4d705e601ad4fde10c5bf1fec414ad1ee6993e4f6b95e01","src/binemit/shrink.rs":"5755efc978f5056a33c0ecb1bd5e08310397f54a67434ecead184fc6ee047133","src/binemit/stackmap.rs":"da3187d96d21b14927279061ccaba4c880d0ad7169b83bd32c1381d45a39af70","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"54b0acb1fb10e98f20804c367d5b2343f8ec918900f8f843e12e0925649b7515","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"6817b893c2c5ba5f2fc4e632fb8f8b7210a9ea9862d389d5247ff94b992b0d27","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/constant.rs":"378d02256c3e21d89b70c6b0956ef70c034a5f14c1d2aaaec1f172a38b7b2279","src/ir/dfg.rs":"03abeb42420006b5d655a396d3724f34507e27e815aec6b30902e5a3fbd52a13","src/ir/entities.rs":"976f51a1e704b63b0bc701eb814b10ec8eee373d8f93ee73ceeeaeeea2c5b821","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"fdbd33def70bfc49648c232d9fdb65eb8ed694a6a1a8bde1e06d6e40d4970230","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"671cc8bfcc347d7409ddba2bc661d985979f144cd663da232d9ba6a54e5c94c5","src/ir/instructions.rs":"7fe853efeb0379486d7878f7925962144ce208d230107d83e5a9165997a07587","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"b80c4609e6101228b6d7fa341b60730137ecdcc2f918120f6473dbf62f31b9ad","src/ir/libcall.rs":"3e540afdd1d9a68b1be0ddb983a8db39312a052aae9ba92fb2440746f69fef06","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"7590a2035a6f88a830e6c440d3c5a22102e921445806d04627e46ee42d82d167","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"8cfe8028008c93c37a593e82c230f95e8674d727cce5715aa55c93e140da4ced","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"bf862e984034f09a83bf0f5f18eb93e09cb23f1a5a994b554c478d174d672c64","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"49b7f398ec8baa2802a283f780bd039e2a630591e74cf1dddc8d9147345c2816","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"56dfbf8f23a82942566d2a81deaf2147777061b3b49532b4f9fdcd3aae51aa56","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"79ecb214ca28d4690b2ace20f6d4cdc36f393ef03f679a9d18a03653d230e160","src/isa/registers.rs":"004b090b7390fa07c1add81ef4a8c79bd7a6001a22cb014a4a83a9fa6ae3aeca","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"41136889df9512d8311f8c015cf3f654557a17d784a17fcefeb0afa2f0ec3674","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"13013f247c8e0fca46fe43568ef3186616fa469a321dee0a41fc2cc25220ec10","src/isa/x86/binemit.rs":"75d88b4ce66ec125940a2543a28e975c542a81a841c3c81282fc98ef78c1e032","src/isa/x86/enc_tables.rs":"ad7e3e384a784c24cc9750bb75f16f3b1cc231ae8f34b6b5d4138ee76d66b2cc","src/isa/x86/mod.rs":"d69e7f441c049b87aa1820639aaf12436bde1b0286757b03bec19fe7492049cc","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"ce25c9575dbc3ef102f199b3bd5652e8c6b88ff323711c89ae41d0070b61adcb","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"7911a03e4229fa6ea371b714b3a50b677adbeeab749b8809bf29fe298cd9d7ff","src/legalizer/split.rs":"696d2a641f52eeb4f2a2106b0641f751f61c560e6e3cbbac544df28b203a4445","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"357c72bc31010fdf0e412000efd7e5538a36361f8562accec6a60e750c111876","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"f52499cc39778f5e935140ea42405ce23e8a2ef9a21faf6378445dcee7e6a0f0","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/branch_splitting.rs":"50ff6a6d257a9cb35d302ed61fa45ff1be4d2ff0f695aa2cedd161bd725a598c","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"6308e0f4f71b24e8d5abc94a98c4d20eff753c02238872119c7f4390f026e0a4","src/regalloc/context.rs":"0b3d5009c23b58cc9ccca2ece9d85dbdea52f843f52452e7813dd7a3229547d3","src/regalloc/diversion.rs":"49edbe958591acb304093e601179de7a79de0a4557748b98ddb736a865ef6a43","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"50399d6569687a87bf1481304aca42506d946e34465e38ca8093e06485ab5fb6","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"739909ac35f48619d67f161ffec30c398d6839797ebea00ba5abd4b0ad0065f0","src/regalloc/reload.rs":"0dc6620ac72545065c14fda91f37bbe7904bf8f99e578d5fe532f1ccc76b9b21","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"3e133a4cd81a029cf34cc329fcaa0169ce6ce4a8642eb5b24faabc4a8a120191","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"865d5cdd7a6e87c8a2e5d41f89ba9c1a95531653363fd43c19a4d80b309534d8","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"a9bbb526efd0f88f35448d2d560cc41c2d804cca46ca1973d2be9e508c016c65","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"f54526eecc1ddc07069900bd3fbcf998abbfb594582bd700423c50ee5fba34b8","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"d3f4422bdea00f1efe7f2b35384f8e3dfa609dee5eae629721d45bedfe087e9f","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"05db00e49552a1ca6cfa0e8ccf38d35778edd0ececc4f20a50b0fb81b37a8312","src/verifier/mod.rs":"8162be3e9008dd661075700285bc9ef39ea0dd152d5fd66c64cf578c214c155d","src/write.rs":"35dff9d0f5ed74779e536cbc6b1de7381cec521a0c54f6d8513041d118bbfc4b"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"3809cc2ba9d09e454815c696dd901849becd4819983b7cd74c17c08360998c2f","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"da415b20c563e636bcccaafb43dbdb77d6c48f9c205b16229865abb1afa40964","src/binemit/mod.rs":"90c56d36091646bba7f0ab1b5064d68b8b0c24ece874fcf8c621830b743e9688","src/binemit/relaxation.rs":"7b1082203c688beab4d705e601ad4fde10c5bf1fec414ad1ee6993e4f6b95e01","src/binemit/shrink.rs":"5755efc978f5056a33c0ecb1bd5e08310397f54a67434ecead184fc6ee047133","src/binemit/stackmap.rs":"f7742f4daafef83a8748f6e5e10cb669eecc4fd18e02e73fdf06d56696b7efa9","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"9c36ff1d2759997e52dd4c5db64423da46ce0cada5166aab29068a378a162f34","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"6817b893c2c5ba5f2fc4e632fb8f8b7210a9ea9862d389d5247ff94b992b0d27","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/constant.rs":"378d02256c3e21d89b70c6b0956ef70c034a5f14c1d2aaaec1f172a38b7b2279","src/ir/dfg.rs":"8539e19a9b7548c8b2d177e9966a2306592aafa89f8bd38763bce53c41b7e95f","src/ir/entities.rs":"e6e5e857f77c59b51ea66888a1a034514dc3686fedc3ccdf453ab9855215d196","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"fdbd33def70bfc49648c232d9fdb65eb8ed694a6a1a8bde1e06d6e40d4970230","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"ce0492c864c6c5dabcfb2716a09f05d6f26cbfb6bbcc8c69c70eeb9e91826ac1","src/ir/instructions.rs":"c65afa7cd6fe48ec8a7e70330e4cc50cca91981dc92eb3715d9b0a06dea20b67","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"e2fa46073f973be1375d005bfe187d50ba353b369d6a8b424cd558d9c61ddd49","src/ir/libcall.rs":"3e540afdd1d9a68b1be0ddb983a8db39312a052aae9ba92fb2440746f69fef06","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"cbe204ea9943ab5a1b4a433cccae49c97122912a48dd26e24d664ae08ae2f63b","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"7098eafab9f8708124bb81507900f26316d34fa8343e465f5a677db8a415978f","src/ir/types.rs":"8cfe8028008c93c37a593e82c230f95e8674d727cce5715aa55c93e140da4ced","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"cfb590b852414c3a3757e4187976944a472a304af518b7921c3f4f750d72609e","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"45aa2f74b323764b6334c09f65b8a27cd82dd1de3cc2d9b207b6d94e55bcbed6","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"56dfbf8f23a82942566d2a81deaf2147777061b3b49532b4f9fdcd3aae51aa56","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"d32ab806081a2bf1ef06f1f9ae6f69846f333d797b6e539a364400c5d7aaeb84","src/isa/registers.rs":"004b090b7390fa07c1add81ef4a8c79bd7a6001a22cb014a4a83a9fa6ae3aeca","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"d7e5e1f4b8ba2a3058d1b416796f6a88522a9472816cb078b5859030f496ac44","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"13013f247c8e0fca46fe43568ef3186616fa469a321dee0a41fc2cc25220ec10","src/isa/x86/binemit.rs":"86622ac2971907d858d9d0a49ff9e51899db8e3f6930dc2ad2ed8c419668a603","src/isa/x86/enc_tables.rs":"b926172bbdaaf1259b0870a2e85228fb50f1274fbe16861b382a963aa00de23d","src/isa/x86/mod.rs":"6ed0ad8a7fa2bec526a99f3b1b9c9fc1cb5f62e5ea49685304e1721c85d81aae","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"6f722a5ba720acdf19c58ba7c9820ea3a5b5017af3bda70adeeeb8b3c1408eb1","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"7911a03e4229fa6ea371b714b3a50b677adbeeab749b8809bf29fe298cd9d7ff","src/legalizer/split.rs":"696d2a641f52eeb4f2a2106b0641f751f61c560e6e3cbbac544df28b203a4445","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"579e060edc61558e05590ce3dd3a65b39a169e0c2b20c47a53fdee14cbbf7146","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"89511e94976129136140515a7229b5d56f524e883c987296872322443d549adb","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/branch_splitting.rs":"50ff6a6d257a9cb35d302ed61fa45ff1be4d2ff0f695aa2cedd161bd725a598c","src/regalloc/coalescing.rs":"334820e453defd28e7aba1c2d6b5db6813bbe228c9a0607c55d1e792c3d8497d","src/regalloc/coloring.rs":"413ad9f6c1efc4775a173e8f3e8255946dbccce57c5ff2e640159f6b247e90c2","src/regalloc/context.rs":"0b3d5009c23b58cc9ccca2ece9d85dbdea52f843f52452e7813dd7a3229547d3","src/regalloc/diversion.rs":"49edbe958591acb304093e601179de7a79de0a4557748b98ddb736a865ef6a43","src/regalloc/live_value_tracker.rs":"34458e7ea99492250faf93adfef7731baed7c1db85483475a256f9b822f8b9cb","src/regalloc/liveness.rs":"1eeae58f9cf1bcf3379de7a1cba9610cd3fe42bc0668181e94cb0a37f1c9a5e2","src/regalloc/liverange.rs":"60f8c9a1707e2db1aa5dae23cc9db46689557556492f14a1b1002bcf0a71de1e","src/regalloc/mod.rs":"50399d6569687a87bf1481304aca42506d946e34465e38ca8093e06485ab5fb6","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"739909ac35f48619d67f161ffec30c398d6839797ebea00ba5abd4b0ad0065f0","src/regalloc/reload.rs":"0dc6620ac72545065c14fda91f37bbe7904bf8f99e578d5fe532f1ccc76b9b21","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"3e133a4cd81a029cf34cc329fcaa0169ce6ce4a8642eb5b24faabc4a8a120191","src/regalloc/spilling.rs":"6bba892c9ba7eafa7e45e5f3925f1a6a5b1023a98e3302bf11ffc65cabb3dd5f","src/regalloc/virtregs.rs":"90e6ddbeb364057a7d2b792c0534e1a3123281b0bd86c5004fe9ead311f5d82a","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"5e342908104df9e9eca8816a01289edc6def8940e97b94ddd14d1cb77afeab31","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"f54526eecc1ddc07069900bd3fbcf998abbfb594582bd700423c50ee5fba34b8","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"674d4f482a9d68a0850d37fcf785ea64802ed30e3efce5a684d6a2c500efc515","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"10f6fd479bc3dca5a018f566620a15e190d7e3cfee9f90e918bafc7e365fe9af","src/verifier/cssa.rs":"1600586748a88843354e76e3f73a2fb837a4c6570eaf1473731e3ea77b87b43a","src/verifier/flags.rs":"2794b0165cc858e9ea2ef0437c5eb1b493754a8dd79f4f876d9eb8a533d5f427","src/verifier/liveness.rs":"97e339f9ff6aeeb304cfda5125ff6c1c693dc96421c8e330f48d4037c9d4fa82","src/verifier/locations.rs":"ed78d5675cf74901e4dbc486058f55a7dd3d21fdc8b0032a92f8a679c78440f0","src/verifier/mod.rs":"3badebb547382f612b3dd8e804f62910f6785b8020b724b7cc6fd15306b1a731","src/write.rs":"20513f9a001cf3505625f065a2098c245877a134adcd5c153257561dd8c5fcde"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen/Cargo.toml
+++ b/third_party/rust/cranelift-codegen/Cargo.toml
@@ -1,39 +1,40 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-codegen"
-version = "0.42.0"
+version = "0.44.0"
 description = "Low-level code generator library"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://cranelift.readthedocs.io/"
 repository = "https://github.com/CraneStation/cranelift"
 categories = ["no-std"]
 readme = "README.md"
 keywords = ["compile", "compiler", "jit"]
 build = "build.rs"
 edition = "2018"
 
 [dependencies]
-cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false }
-cranelift-bforest = { path = "../cranelift-bforest", version = "0.42.0", default-features = false }
+cranelift-codegen-shared = { path = "./shared", version = "0.44.0" }
+cranelift-entity = { path = "../cranelift-entity", version = "0.44.0", default-features = false }
+cranelift-bforest = { path = "../cranelift-bforest", version = "0.44.0", default-features = false }
 failure = { version = "0.1.1", default-features = false, features = ["derive"] }
 failure_derive = { version = "0.1.1", default-features = false }
 hashmap_core = { version = "0.1.9", optional = true }
 target-lexicon = "0.8.1"
 log = { version = "0.4.6", default-features = false }
 serde = { version = "1.0.94", features = ["derive"], optional = true }
 smallvec = { version = "0.6.10" }
 # It is a goal of the cranelift-codegen crate to have minimal external dependencies.
 # Please don't add any unless they are essential to the task of creating binary
 # machine code. Integration tests that need external dependencies can be
 # accomodated in `tests`.
 
 [build-dependencies]
-cranelift-codegen-meta = { path = "meta", version = "0.42.0", default-features = false }
+cranelift-codegen-meta = { path = "meta", version = "0.44.0", default-features = false }
 
 [features]
 default = ["std"]
 
 # The "std" feature enables use of libstd. The "core" feature enables use
 # of some minimal std-like replacement libraries. At least one of these two
 # features need to be enabled.
 std = [
--- a/third_party/rust/cranelift-codegen/src/binemit/stackmap.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/stackmap.rs
@@ -1,17 +1,20 @@
 use crate::bitset::BitSet;
 use crate::ir;
 use crate::isa::TargetIsa;
 use std::vec::Vec;
 
+type Num = u32;
+const NUM_BITS: usize = std::mem::size_of::<Num>() * 8;
+
 /// Wrapper class for longer bit vectors that cannot be represented by a single BitSet.
 #[derive(Clone, Debug)]
 pub struct Stackmap {
-    bitmap: Vec<BitSet<u32>>,
+    bitmap: Vec<BitSet<Num>>,
 }
 
 impl Stackmap {
     /// Create a stackmap based on where references are located on a function's stack.
     pub fn from_values(
         args: &[ir::entities::Value],
         func: &ir::Function,
         isa: &dyn TargetIsa,
@@ -47,75 +50,73 @@ impl Stackmap {
         for (ss, ssd) in stack.iter() {
             if live_ref_in_stack_slot.contains(&ss) {
                 // Assumption: greater magnitude of offset imply higher address.
                 let index = (((ssd.offset.unwrap().abs() as u32) - ssd.size) / word_size) as usize;
                 vec[index] = true;
             }
         }
 
-        Stackmap::from_vec(&vec)
+        Stackmap::from_slice(&vec)
     }
 
-    /// Create a vec of Bitsets from a vec of bools.
-    pub fn from_vec(vec: &Vec<bool>) -> Self {
-        let mut rem = vec.len();
-        let num_word = ((rem as f32) / 32.0).ceil() as usize;
+    /// Create a vec of Bitsets from a slice of bools.
+    pub fn from_slice(vec: &[bool]) -> Self {
+        let len = vec.len();
+        let num_word = len / NUM_BITS + (len % NUM_BITS != 0) as usize;
         let mut bitmap = Vec::with_capacity(num_word);
 
-        for i in 0..num_word {
+        for segment in vec.chunks(NUM_BITS) {
             let mut curr_word = 0;
-            let count = if rem > 32 { 32 } else { rem };
-            for j in 0..count {
-                if vec[i * 32 + j] {
-                    curr_word |= 1 << j;
+            for (i, set) in segment.iter().enumerate() {
+                if *set {
+                    curr_word |= 1 << i;
                 }
             }
-            bitmap.push(BitSet::<u32>(curr_word));
-            rem -= count;
+            bitmap.push(BitSet(curr_word));
         }
         Self { bitmap }
     }
 
     /// Returns a specified bit.
     pub fn get_bit(&self, bit_index: usize) -> bool {
-        assert!(bit_index < 32 * self.bitmap.len());
-        let word_index = bit_index / 32;
-        let word_offset = (bit_index % 32) as u8;
+        assert!(bit_index < NUM_BITS * self.bitmap.len());
+        let word_index = bit_index / NUM_BITS;
+        let word_offset = (bit_index % NUM_BITS) as u8;
         self.bitmap[word_index].contains(word_offset)
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
     fn stackmaps() {
         let vec: Vec<bool> = Vec::new();
-        assert!(Stackmap::from_vec(&vec).bitmap.is_empty());
+        assert!(Stackmap::from_slice(&vec).bitmap.is_empty());
 
-        let mut vec: [bool; 32] = Default::default();
+        let mut vec: [bool; NUM_BITS] = Default::default();
         let set_true_idx = [5, 7, 24, 31];
 
-        for idx in set_true_idx.iter() {
-            vec[*idx] = true;
+        for &idx in &set_true_idx {
+            vec[idx] = true;
         }
 
         let mut vec = vec.to_vec();
         assert_eq!(
-            vec![BitSet::<u32>(2164261024)],
-            Stackmap::from_vec(&vec).bitmap
+            vec![BitSet::<Num>(2164261024)],
+            Stackmap::from_slice(&vec).bitmap
         );
 
         vec.push(false);
         vec.push(true);
-        let res = Stackmap::from_vec(&vec);
+        let res = Stackmap::from_slice(&vec);
         assert_eq!(
-            vec![BitSet::<u32>(2164261024), BitSet::<u32>(2)],
+            vec![BitSet::<Num>(2164261024), BitSet::<Num>(2)],
             res.bitmap
         );
 
         assert!(res.get_bit(5));
         assert!(res.get_bit(31));
         assert!(res.get_bit(33));
         assert!(!res.get_bit(1));
     }
--- a/third_party/rust/cranelift-codegen/src/context.rs
+++ b/third_party/rust/cranelift-codegen/src/context.rs
@@ -127,42 +127,44 @@ impl Context {
     /// code sink.
     ///
     /// Returns information about the function's code and read-only data.
     pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
         let _tt = timing::compile();
         self.verify_if(isa)?;
         debug!("Compiling:\n{}", self.func.display(isa));
 
+        let opt_level = isa.flags().opt_level();
+
         self.compute_cfg();
-        if isa.flags().opt_level() != OptLevel::Fastest {
+        if opt_level != OptLevel::None {
             self.preopt(isa)?;
         }
         if isa.flags().enable_nan_canonicalization() {
             self.canonicalize_nans(isa)?;
         }
         self.legalize(isa)?;
-        if isa.flags().opt_level() != OptLevel::Fastest {
+        if opt_level != OptLevel::None {
             self.postopt(isa)?;
-        }
-        if isa.flags().opt_level() == OptLevel::Best {
             self.compute_domtree();
             self.compute_loop_analysis();
             self.licm(isa)?;
             self.simple_gvn(isa)?;
         }
         self.compute_domtree();
         self.eliminate_unreachable_code(isa)?;
-        if isa.flags().opt_level() != OptLevel::Fastest {
+        if opt_level != OptLevel::None {
             self.dce(isa)?;
         }
         self.regalloc(isa)?;
         self.prologue_epilogue(isa)?;
-        if isa.flags().opt_level() == OptLevel::Best {
+        if opt_level == OptLevel::Speed || opt_level == OptLevel::SpeedAndSize {
             self.redundant_reload_remover(isa)?;
+        }
+        if opt_level == OptLevel::SpeedAndSize {
             self.shrink_instructions(isa)?;
         }
         let result = self.relax_branches(isa);
 
         debug!("Compiled:\n{}", self.func.display(isa));
         result
     }
 
--- a/third_party/rust/cranelift-codegen/src/ir/dfg.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/dfg.rs
@@ -1,29 +1,30 @@
 //! Data flow graph tracking Instructions, Values, and EBBs.
 
 use crate::entity::{self, PrimaryMap, SecondaryMap};
 use crate::ir;
 use crate::ir::builder::ReplaceBuilder;
 use crate::ir::extfunc::ExtFuncData;
 use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData};
-use crate::ir::{types, ConstantPool};
+use crate::ir::{types, ConstantPool, Immediate};
 use crate::ir::{
     Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments, ValueList,
     ValueListPool,
 };
 use crate::isa::TargetIsa;
 use crate::packed_option::ReservedValue;
 use crate::write::write_operands;
 use core::fmt;
 use core::iter;
 use core::mem;
 use core::ops::{Index, IndexMut};
 use core::u16;
 use std::collections::HashMap;
+use std::vec::Vec;
 
 /// A data flow graph defines all instructions and extended basic blocks in a function as well as
 /// the data flow dependencies between them. The DFG also tracks values which can be either
 /// instruction results or EBB parameters.
 ///
 /// The layout of EBBs in the function and of instructions in each EBB is recorded by the
 /// `Layout` data structure which forms the other half of the function representation.
 ///
@@ -65,45 +66,50 @@ pub struct DataFlowGraph {
     /// External function references. These are functions that can be called directly.
     pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>,
 
     /// Saves Value labels.
     pub values_labels: Option<HashMap<Value, ValueLabelAssignments>>,
 
     /// Constants used within the function
     pub constants: ConstantPool,
+
+    /// Stores large immediates that otherwise will not fit on InstructionData
+    pub immediates: PrimaryMap<Immediate, Vec<u8>>,
 }
 
 impl DataFlowGraph {
     /// Create a new empty `DataFlowGraph`.
     pub fn new() -> Self {
         Self {
             insts: PrimaryMap::new(),
             results: SecondaryMap::new(),
             ebbs: PrimaryMap::new(),
             value_lists: ValueListPool::new(),
             values: PrimaryMap::new(),
             signatures: PrimaryMap::new(),
             ext_funcs: PrimaryMap::new(),
             values_labels: None,
             constants: ConstantPool::new(),
+            immediates: PrimaryMap::new(),
         }
     }
 
     /// Clear everything.
     pub fn clear(&mut self) {
         self.insts.clear();
         self.results.clear();
         self.ebbs.clear();
         self.value_lists.clear();
         self.values.clear();
         self.signatures.clear();
         self.ext_funcs.clear();
         self.values_labels = None;
-        self.constants.clear()
+        self.constants.clear();
+        self.immediates.clear();
     }
 
     /// Get the total number of instructions created in this function, whether they are currently
     /// inserted in the layout or not.
     ///
     /// This is intended for use with `SecondaryMap::with_capacity`.
     pub fn num_insts(&self) -> usize {
         self.insts.len()
--- a/third_party/rust/cranelift-codegen/src/ir/entities.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/entities.rs
@@ -20,17 +20,22 @@
 //! format.
 
 use crate::entity::entity_impl;
 use core::fmt;
 use core::u32;
 #[cfg(feature = "enable-serde")]
 use serde::{Deserialize, Serialize};
 
-/// An opaque reference to an extended basic block in a function.
+/// An opaque reference to an [extended basic
+/// block](https://en.wikipedia.org/wiki/Extended_basic_block) in a
+/// [`Function`](super::function::Function).
+///
+/// You can get an `Ebb` using
+/// [`FunctionBuilder::create_ebb`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_ebb)
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct Ebb(u32);
 entity_impl!(Ebb, "ebb");
 
 impl Ebb {
     /// Create a new EBB reference from its number. This corresponds to the `ebbNN` representation.
     ///
     /// This method is for use by the parser.
@@ -39,16 +44,28 @@ impl Ebb {
             Some(Ebb(n))
         } else {
             None
         }
     }
 }
 
 /// An opaque reference to an SSA value.
+///
+/// You can get a constant `Value` from the following
+/// [`InstBuilder`](super::InstBuilder) instructions:
+///
+/// - [`iconst`](super::InstBuilder::iconst) for integer constants
+/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
+/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
+/// - [`bconst`](super::InstBuilder::bconst) for boolean constants
+/// - [`vconst`](super::InstBuilder::vconst) for vector constants
+/// - [`null`](super::InstBuilder::null) for null reference constants
+///
+/// Any `InstBuilder` instruction that has an output will also return a `Value`.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct Value(u32);
 entity_impl!(Value, "v");
 
 impl Value {
     /// Create a value from its number representation.
     /// This is the number in the `vNN` notation.
     ///
@@ -57,22 +74,44 @@ impl Value {
         if n < u32::MAX / 2 {
             Some(Value(n))
         } else {
             None
         }
     }
 }
 
-/// An opaque reference to an instruction in a function.
+/// An opaque reference to an instruction in a [`Function`](super::Function).
+///
+/// Most usage of `Inst` is internal. `Inst`ructions are returned by
+/// [`InstBuilder`](super::InstBuilder) instructions that do not return a
+/// [`Value`], such as control flow and trap instructions.
+///
+/// If you look around the API, you can find many inventive uses for `Inst`,
+/// such as [annotating specific instructions with a comment][inst_comment]
+/// or [performing reflection at compile time](super::DataFlowGraph::analyze_branch)
+/// on the type of instruction.
+///
+/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct Inst(u32);
 entity_impl!(Inst, "inst");
 
 /// An opaque reference to a stack slot.
+///
+/// Stack slots represent an address on the
+/// [call stack](https://en.wikipedia.org/wiki/Call_stack).
+///
+/// `StackSlot`s can be created with
+/// [`FunctionBuilder::create_stackslot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_stack_slot).
+///
+/// `StackSlot`s are most often used with
+/// [`stack_addr`](super::InstBuilder::stack_addr),
+/// [`stack_load`](super::InstBuilder::stack_load), and
+/// [`stack_store`](super::InstBuilder::stack_store).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub struct StackSlot(u32);
 entity_impl!(StackSlot, "ss");
 
 impl StackSlot {
     /// Create a new stack slot reference from its number.
     ///
@@ -82,16 +121,32 @@ impl StackSlot {
             Some(StackSlot(n))
         } else {
             None
         }
     }
 }
 
 /// An opaque reference to a global value.
+///
+/// A `GlobalValue` is a [`Value`](Value) that will be live across the entire
+/// function lifetime. It can be preloaded from other global values.
+///
+/// You can create a `GlobalValue` in the following ways:
+///
+/// - When compiling to WASM, you can use it to load values from a
+/// [`VmContext`](super::GlobalValueData::VMContext) using
+/// [`FuncEnvironment::make_global`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_global).
+/// - When compiling to native code, you can use it for objects in static memory with
+/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html#method.declare_data_in_func).
+/// - For any compilation target, it can be registered with
+/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).
+///
+/// `GlobalValue`s can be retrieved with
+/// [`InstBuilder:global_value`](super::InstBuilder::global_value).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct GlobalValue(u32);
 entity_impl!(GlobalValue, "gv");
 
 impl GlobalValue {
     /// Create a new global value reference from its number.
     ///
     /// This method is for use by the parser.
@@ -99,17 +154,21 @@ impl GlobalValue {
         if n < u32::MAX {
             Some(GlobalValue(n))
         } else {
             None
         }
     }
 }
 
-/// An opaque reference to a constant
+/// An opaque reference to a constant.
+///
+/// You can store [`ConstantData`](super::ConstantData) in a
+/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
+/// See [`ConstantPool::insert`](super::ConstantPool::insert).
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct Constant(u32);
 entity_impl!(Constant, "const");
 
 impl Constant {
     /// Create a const reference from its number.
     ///
     /// This method is for use by the parser.
@@ -117,17 +176,49 @@ impl Constant {
         if n < u32::MAX {
             Some(Constant(n))
         } else {
             None
         }
     }
 }
 
-/// An opaque reference to a jump table.
+/// An opaque reference to an immediate.
+///
+/// Some immediates (e.g. SIMD shuffle masks) are too large to store in the
+/// [`InstructionData`](super::instructions::InstructionData) struct and therefore must be
+/// tracked separately in [`DataFlowGraph::immediates`](super::dfg::DataFlowGraph). `Immediate`
+/// provides a way to reference values stored there.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Immediate(u32);
+entity_impl!(Immediate, "imm");
+
+impl Immediate {
+    /// Create an immediate reference from its number.
+    ///
+    /// This method is for use by the parser.
+    pub fn with_number(n: u32) -> Option<Self> {
+        if n < u32::MAX {
+            Some(Immediate(n))
+        } else {
+            None
+        }
+    }
+}
+
+/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
+///
+/// `JumpTable`s are used for indirect branching and are specialized for dense,
+/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
+/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
+///
+/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
+///
+/// `JumpTable`s can be created with
+/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub struct JumpTable(u32);
 entity_impl!(JumpTable, "jt");
 
 impl JumpTable {
     /// Create a new jump table reference from its number.
     ///
@@ -136,17 +227,32 @@ impl JumpTable {
         if n < u32::MAX {
             Some(JumpTable(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to an external function.
+/// An opaque reference to another [`Function`](super::Function).
+///
+/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
+/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
+/// [indirect](super::InstBuilder::call_indirect) function calls.
+///
+/// `FuncRef`s can be created with
+///
+/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
+/// for external functions
+/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html#method.declare_func_in_func)
+/// for functions declared elsewhere in the same native
+/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html)
+/// - [`FuncEnvironment::make_direct_func`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
+/// for functions declared in the same WebAssembly
+/// [`FuncEnvironment`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct FuncRef(u32);
 entity_impl!(FuncRef, "fn");
 
 impl FuncRef {
     /// Create a new external function reference from its number.
     ///
     /// This method is for use by the parser.
@@ -154,17 +260,28 @@ impl FuncRef {
         if n < u32::MAX {
             Some(FuncRef(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to a function signature.
+/// An opaque reference to a function [`Signature`](super::Signature).
+///
+/// `SigRef`s are used to declare a function with
+/// [`FunctionBuiler::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
+/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
+///
+/// `SigRef`s can be created with
+/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
+///
+/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
+/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
+/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct SigRef(u32);
 entity_impl!(SigRef, "sig");
 
 impl SigRef {
     /// Create a new function signature reference from its number.
     ///
     /// This method is for use by the parser.
@@ -172,17 +289,22 @@ impl SigRef {
         if n < u32::MAX {
             Some(SigRef(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to a heap.
+/// An opaque reference to a [heap](https://en.wikipedia.org/wiki/Memory_management#DYNAMIC).
+///
+/// Heaps are used to access dynamically allocated memory through
+/// [`heap_addr`](super::InstBuilder::heap_addr).
+///
+/// To create a heap, use [`FunctionBuilder::create_heap`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_heap).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Heap(u32);
 entity_impl!(Heap, "heap");
 
 impl Heap {
     /// Create a new heap reference from its number.
     ///
     /// This method is for use by the parser.
@@ -190,17 +312,23 @@ impl Heap {
         if n < u32::MAX {
             Some(Heap(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to a table.
+/// An opaque reference to a [WebAssembly
+/// table](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables).
+///
+/// `Table`s are used to store a list of function references.
+/// They can be created with [`FuncEnvironment::make_table`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_table).
+/// They can be used with
+/// [`FuncEnvironment::translate_call_indirect`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.translate_call_indirect).
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Table(u32);
 entity_impl!(Table, "table");
 
 impl Table {
     /// Create a new table reference from its number.
     ///
     /// This method is for use by the parser.
@@ -208,17 +336,17 @@ impl Table {
         if n < u32::MAX {
             Some(Table(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to any of the entities defined in this module that can appear in CLIF IR.
+/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum AnyEntity {
     /// The whole function.
     Function,
     /// An extended basic block.
     Ebb(Ebb),
     /// An instruction.
     Inst(Inst),
--- a/third_party/rust/cranelift-codegen/src/ir/immediates.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/immediates.rs
@@ -1,17 +1,16 @@
 //! Immediate operands for Cranelift instructions
 //!
 //! This module defines the types of immediate operands that can appear on Cranelift instructions.
 //! Each type here should have a corresponding definition in the
 //! `cranelift-codegen/meta/src/shared/immediates` crate in the meta language.
 
 use core::fmt::{self, Display, Formatter};
 use core::iter::FromIterator;
-use core::mem;
 use core::str::{from_utf8, FromStr};
 use core::{i32, u32};
 use std::vec::Vec;
 
 /// Convert a type into a vector of bytes; all implementors in this file must use little-endian
 /// orderings of bytes to match WebAssembly's little-endianness.
 trait IntoBytes {
     fn into_bytes(self) -> Vec<u8>;
@@ -285,40 +284,40 @@ impl FromStr for Uimm32 {
                 Ok(Uimm32(x as u32))
             } else {
                 Err("Uimm32 out of range")
             }
         })
     }
 }
 
-/// A 128-bit unsigned integer immediate operand.
+/// A 128-bit immediate operand.
 ///
 /// This is used as an immediate value in SIMD instructions.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Uimm128(pub [u8; 16]);
+pub struct V128Imm(pub [u8; 16]);
 
-impl Uimm128 {
+impl V128Imm {
     /// Iterate over the bytes in the constant
     pub fn bytes(&self) -> impl Iterator<Item = &u8> {
         self.0.iter()
     }
 
     /// Convert the immediate into a vector
     pub fn to_vec(self) -> Vec<u8> {
         self.0.to_vec()
     }
 
     /// Convert the immediate into a slice
     pub fn as_slice(&self) -> &[u8] {
         &self.0[..]
     }
 }
 
-impl Display for Uimm128 {
+impl Display for V128Imm {
     // Print a 128-bit vector in hexadecimal, e.g. 0x000102030405060708090a0b0c0d0e0f.
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         write!(f, "0x")?;
         let mut anything_written = false;
         for &b in self.0.iter().rev() {
             if b == 0 && !anything_written {
                 continue;
             } else {
@@ -328,34 +327,34 @@ impl Display for Uimm128 {
         }
         if !anything_written {
             write!(f, "00")?;
         }
         Ok(())
     }
 }
 
-impl From<u64> for Uimm128 {
+impl From<u64> for V128Imm {
     fn from(x: u64) -> Self {
         let mut buffer: [u8; 16] = [0; 16]; // zero-fill
         (0..8).for_each(|byte| buffer[byte] = (x >> (byte as u64 * 8) & 0xff) as u8); // insert each byte from the u64 into v in little-endian order
-        Uimm128(buffer)
+        V128Imm(buffer)
     }
 }
 
-impl From<&[u8]> for Uimm128 {
+impl From<&[u8]> for V128Imm {
     fn from(slice: &[u8]) -> Self {
         assert_eq!(slice.len(), 16);
         let mut buffer = [0; 16];
         buffer.copy_from_slice(slice);
-        Uimm128(buffer)
+        V128Imm(buffer)
     }
 }
 
-impl FromStr for Uimm128 {
+impl FromStr for V128Imm {
     type Err = &'static str;
 
     // parse a 128-bit vector from a hexadecimal string, formatted as above
     fn from_str(s: &str) -> Result<Self, &'static str> {
         if s.len() <= 2 || &s[0..2] != "0x" {
             Err("Expected a hexadecimal string, e.g. 0x1234")
         } else {
             // clean and check the string
@@ -379,58 +378,58 @@ impl FromStr for Uimm128 {
                     let pair = from_utf8(&cleaned[i..i + 2])
                         .or_else(|_| Err("Unable to parse hexadecimal pair as UTF-8"))?;
                     let byte = u8::from_str_radix(pair, 16)
                         .or_else(|_| Err("Unable to parse as hexadecimal"))?;
                     buffer[position] = byte;
                     position = position.wrapping_sub(1); // should only wrap on the last iteration
                 }
 
-                Ok(Uimm128(buffer))
+                Ok(V128Imm(buffer))
             }
         }
     }
 }
 
 /// Implement a way to convert an iterator of immediates to a Uimm128:
 ///  - this expects the items in reverse order (e.g. last lane first) which is the natural output of pushing items into a vector
 ///  - this may not fully consume the iterator or may fail if it cannot take the expected number of items
 ///  - this requires the input type (i.e. $ty) to implement ToBytes
 macro_rules! construct_uimm128_from_iterator_of {
     ( $ty:ident, $lanes:expr ) => {
-        impl FromIterator<$ty> for Uimm128 {
+        impl FromIterator<$ty> for V128Imm {
             fn from_iter<T: IntoIterator<Item = $ty>>(iter: T) -> Self {
                 let mut buffer: [u8; 16] = [0; 16];
                 iter.into_iter()
                     .take($lanes)
                     .map(|f| f.into_bytes())
                     .flat_map(|b| b)
                     .enumerate()
                     .for_each(|(i, b)| buffer[i] = b);
-                Uimm128(buffer)
+                V128Imm(buffer)
             }
         }
     };
 }
 
 /// Special case for booleans since we have to decide the bit-width based on the number of items
-impl FromIterator<bool> for Uimm128 {
+impl FromIterator<bool> for V128Imm {
     fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
         let bools = Vec::from_iter(iter);
         let count = bools.len();
         assert!(count > 0 && count <= 16); // ensure we don't have too many booleans
         assert_eq!(count & (count - 1), 0); // ensure count is a power of two, see https://stackoverflow.com/questions/600293
         let mut buffer: [u8; 16] = [0; 16];
         let step = 16 / count;
         bools
             .iter()
             .enumerate()
             .map(|(i, &b)| (i * step, if b { 1 } else { 0 }))
             .for_each(|(i, b)| buffer[i] = b);
-        Uimm128(buffer)
+        V128Imm(buffer)
     }
 }
 
 construct_uimm128_from_iterator_of!(u8, 16);
 construct_uimm128_from_iterator_of!(i32, 4);
 construct_uimm128_from_iterator_of!(Ieee32, 4);
 construct_uimm128_from_iterator_of!(Imm64, 2);
 construct_uimm128_from_iterator_of!(Ieee64, 2);
@@ -804,17 +803,17 @@ impl Ieee32 {
 
     /// Return self negated.
     pub fn neg(self) -> Self {
         Ieee32(self.0 ^ (1 << 31))
     }
 
     /// Create a new `Ieee32` representing the number `x`.
     pub fn with_float(x: f32) -> Self {
-        Ieee32(unsafe { mem::transmute(x) })
+        Ieee32(x.to_bits())
     }
 
     /// Get the bitwise representation.
     pub fn bits(self) -> u32 {
         self.0
     }
 }
 
@@ -877,17 +876,17 @@ impl Ieee64 {
 
     /// Return self negated.
     pub fn neg(self) -> Self {
         Ieee64(self.0 ^ (1 << 63))
     }
 
     /// Create a new `Ieee64` representing the number `x`.
     pub fn with_float(x: f64) -> Self {
-        Ieee64(unsafe { mem::transmute(x) })
+        Ieee64(x.to_bits())
     }
 
     /// Get the bitwise representation.
     pub fn bits(self) -> u64 {
         self.0
     }
 }
 
@@ -926,16 +925,17 @@ impl IntoBytes for Ieee64 {
         self.0.to_le_bytes().to_vec()
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use core::fmt::Display;
+    use core::mem;
     use core::str::FromStr;
     use core::{f32, f64};
     use std::string::ToString;
 
     #[test]
     fn format_imm64() {
         assert_eq!(Imm64(0).to_string(), "0");
         assert_eq!(Imm64(9999).to_string(), "9999");
@@ -1064,118 +1064,118 @@ mod tests {
         parse_err::<Uimm64>("-1", "Invalid character in decimal number");
 
         // Hex count overflow.
         parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
     }
 
     #[test]
     fn format_uimm128() {
-        assert_eq!(Uimm128::from(0).to_string(), "0x00");
-        assert_eq!(Uimm128::from(42).to_string(), "0x2a");
-        assert_eq!(Uimm128::from(3735928559).to_string(), "0xdeadbeef");
+        assert_eq!(V128Imm::from(0).to_string(), "0x00");
+        assert_eq!(V128Imm::from(42).to_string(), "0x2a");
+        assert_eq!(V128Imm::from(3735928559).to_string(), "0xdeadbeef");
         assert_eq!(
-            Uimm128::from(0x0102030405060708).to_string(),
+            V128Imm::from(0x0102030405060708).to_string(),
             "0x0102030405060708"
         );
     }
 
     #[test]
     fn parse_uimm128() {
-        parse_ok::<Uimm128>("0x00", "0x00");
-        parse_ok::<Uimm128>("0x00000042", "0x42");
-        parse_ok::<Uimm128>(
+        parse_ok::<V128Imm>("0x00", "0x00");
+        parse_ok::<V128Imm>("0x00000042", "0x42");
+        parse_ok::<V128Imm>(
             "0x0102030405060708090a0b0c0d0e0f00",
             "0x0102030405060708090a0b0c0d0e0f00",
         );
-        parse_ok::<Uimm128>("0x_0000_0043_21", "0x4321");
+        parse_ok::<V128Imm>("0x_0000_0043_21", "0x4321");
 
-        parse_err::<Uimm128>("", "Expected a hexadecimal string, e.g. 0x1234");
-        parse_err::<Uimm128>("0x", "Expected a hexadecimal string, e.g. 0x1234");
-        parse_err::<Uimm128>(
+        parse_err::<V128Imm>("", "Expected a hexadecimal string, e.g. 0x1234");
+        parse_err::<V128Imm>("0x", "Expected a hexadecimal string, e.g. 0x1234");
+        parse_err::<V128Imm>(
             "0x042",
             "Hexadecimal string must have an even number of digits",
         );
-        parse_err::<Uimm128>(
+        parse_err::<V128Imm>(
             "0x00000000000000000000000000000000000000000000000000",
             "Hexadecimal string has too many digits to fit in a 128-bit vector",
         );
-        parse_err::<Uimm128>("0xrstu", "Unable to parse as hexadecimal");
-        parse_err::<Uimm128>("0x__", "Hexadecimal string must have some digits");
+        parse_err::<V128Imm>("0xrstu", "Unable to parse as hexadecimal");
+        parse_err::<V128Imm>("0x__", "Hexadecimal string must have some digits");
     }
 
     #[test]
     fn uimm128_equivalence() {
         assert_eq!(
-            "0x01".parse::<Uimm128>().unwrap().0,
+            "0x01".parse::<V128Imm>().unwrap().0,
             [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
         assert_eq!(
-            Uimm128::from_iter(vec![1, 0, 0, 0]).0,
+            V128Imm::from_iter(vec![1, 0, 0, 0]).0,
             [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
         assert_eq!(
-            Uimm128::from(1).0,
+            V128Imm::from(1).0,
             [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
     }
 
     #[test]
     fn uimm128_endianness() {
         assert_eq!(
-            "0x42".parse::<Uimm128>().unwrap().0,
+            "0x42".parse::<V128Imm>().unwrap().0,
             [0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
         assert_eq!(
-            "0x00".parse::<Uimm128>().unwrap().0,
+            "0x00".parse::<V128Imm>().unwrap().0,
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
         assert_eq!(
-            "0x12345678".parse::<Uimm128>().unwrap().0,
+            "0x12345678".parse::<V128Imm>().unwrap().0,
             [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
         assert_eq!(
-            "0x1234_5678".parse::<Uimm128>().unwrap().0,
+            "0x1234_5678".parse::<V128Imm>().unwrap().0,
             [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
         );
     }
 
     #[test]
     fn uimm128_from_iter() {
         assert_eq!(
-            Uimm128::from_iter(vec![4, 3, 2, 1]).0,
+            V128Imm::from_iter(vec![4, 3, 2, 1]).0,
             [4, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0]
         );
 
         assert_eq!(
-            Uimm128::from_iter(vec![false, true]).0,
+            V128Imm::from_iter(vec![false, true]).0,
             [/* false */ 0, 0, 0, 0, 0, 0, 0, 0, /* true */ 1, 0, 0, 0, 0, 0, 0, 0]
         );
 
         assert_eq!(
-            Uimm128::from_iter(vec![false, true, false, true, false, true, false, true]).0,
+            V128Imm::from_iter(vec![false, true, false, true, false, true, false, true]).0,
             [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
         );
 
         #[allow(trivial_numeric_casts)]
         let u8s = vec![
             1 as u8, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0,
         ];
         assert_eq!(
-            Uimm128::from_iter(u8s).0,
+            V128Imm::from_iter(u8s).0,
             [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
         );
 
         #[allow(trivial_numeric_casts)]
         let ieee32s: Vec<Ieee32> = vec![32.4 as f32, 0.0, 1.0, 6.6666]
             .iter()
             .map(|&f| Ieee32::from(f))
             .collect();
         assert_eq!(
-            Uimm128::from_iter(ieee32s).0,
+            V128Imm::from_iter(ieee32s).0,
             [
                 /* 32.4 == */ 0x9a, 0x99, 0x01, 0x42, /* 0 == */ 0, 0, 0, 0,
                 /* 1 == */ 0, 0, 0x80, 0x3f, /* 6.6666 == */ 0xca, 0x54, 0xd5, 0x40,
             ]
         )
     }
 
     #[test]
--- a/third_party/rust/cranelift-codegen/src/ir/instructions.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/instructions.rs
@@ -13,17 +13,16 @@ use std::vec::Vec;
 
 use crate::ir;
 use crate::ir::types;
 use crate::ir::{Ebb, FuncRef, JumpTable, SigRef, Type, Value};
 use crate::isa;
 
 use crate::bitset::BitSet;
 use crate::entity;
-use crate::ref_slice::{ref_slice, ref_slice_mut};
 
 /// Some instructions use an external list of argument values because there is not enough space in
 /// the 16-byte `InstructionData` struct. These value lists are stored in a memory pool in
 /// `dfg.value_lists`.
 pub type ValueList = entity::EntityList<Value>;
 
 /// Memory pool for holding value lists. See `ValueList`.
 pub type ValueListPool = entity::ListPool<Value>;
--- a/third_party/rust/cranelift-codegen/src/ir/layout.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/layout.rs
@@ -693,17 +693,17 @@ impl Layout {
         }
 
         self.assign_ebb_seq(new_ebb);
     }
 }
 
 #[derive(Clone, Debug, Default)]
 struct InstNode {
-    // The Ebb containing this instruction, or `None` if the instruction is not yet inserted.
+    /// The Ebb containing this instruction, or `None` if the instruction is not yet inserted.
     ebb: PackedOption<Ebb>,
     prev: PackedOption<Inst>,
     next: PackedOption<Inst>,
     seq: SequenceNumber,
 }
 
 /// Iterate over instructions in an EBB in layout order. See `Layout::ebb_insts()`.
 pub struct Insts<'f> {
--- a/third_party/rust/cranelift-codegen/src/ir/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/mod.rs
@@ -1,12 +1,11 @@
 //! Representation of Cranelift IR functions.
 
 mod builder;
-pub mod condcodes;
 pub mod constant;
 pub mod dfg;
 pub mod entities;
 mod extfunc;
 mod extname;
 pub mod function;
 mod globalvalue;
 mod heap;
@@ -26,17 +25,18 @@ mod valueloc;
 
 #[cfg(feature = "enable-serde")]
 use serde::{Deserialize, Serialize};
 
 pub use crate::ir::builder::{InsertBuilder, InstBuilder, InstBuilderBase, InstInserterBase};
 pub use crate::ir::constant::{ConstantData, ConstantOffset, ConstantPool};
 pub use crate::ir::dfg::{DataFlowGraph, ValueDef};
 pub use crate::ir::entities::{
-    Constant, Ebb, FuncRef, GlobalValue, Heap, Inst, JumpTable, SigRef, StackSlot, Table, Value,
+    Constant, Ebb, FuncRef, GlobalValue, Heap, Immediate, Inst, JumpTable, SigRef, StackSlot,
+    Table, Value,
 };
 pub use crate::ir::extfunc::{
     AbiParam, ArgumentExtension, ArgumentPurpose, ExtFuncData, Signature,
 };
 pub use crate::ir::extname::ExternalName;
 pub use crate::ir::function::{DisplayFunctionAnnotations, Function};
 pub use crate::ir::globalvalue::GlobalValueData;
 pub use crate::ir::heap::{HeapData, HeapStyle};
@@ -49,16 +49,17 @@ pub use crate::ir::libcall::{get_libcall
 pub use crate::ir::memflags::MemFlags;
 pub use crate::ir::progpoint::{ExpandedProgramPoint, ProgramOrder, ProgramPoint};
 pub use crate::ir::sourceloc::SourceLoc;
 pub use crate::ir::stackslot::{StackSlotData, StackSlotKind, StackSlots};
 pub use crate::ir::table::TableData;
 pub use crate::ir::trapcode::TrapCode;
 pub use crate::ir::types::Type;
 pub use crate::ir::valueloc::{ArgumentLoc, ValueLoc};
+pub use cranelift_codegen_shared::condcodes;
 
 use crate::binemit;
 use crate::entity::{entity_impl, PrimaryMap, SecondaryMap};
 use crate::isa;
 
 /// Map of value locations.
 pub type ValueLocations = SecondaryMap<Value, ValueLoc>;
 
--- a/third_party/rust/cranelift-codegen/src/ir/trapcode.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/trapcode.rs
@@ -1,17 +1,20 @@
 //! Trap codes describing the reason for a trap.
 
 use core::fmt::{self, Display, Formatter};
 use core::str::FromStr;
+#[cfg(feature = "enable-serde")]
+use serde::{Deserialize, Serialize};
 
 /// A trap code describing the reason for a trap.
 ///
 /// All trap instructions have an explicit trap code.
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub enum TrapCode {
     /// The current stack space was exhausted.
     ///
     /// On some platforms, a stack overflow may also be indicated by a segmentation fault from the
     /// stack guard page.
     StackOverflow,
 
     /// A `heap_addr` instruction detected an out-of-bounds error.
--- a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
@@ -121,15 +121,23 @@ impl TargetIsa for Isa {
         sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink, self)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink, self)
     }
+
+    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedLessThan
+    }
+
+    fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedGreaterThanOrEqual
+    }
 }
 
 impl fmt::Display for Isa {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}\n{}", self.shared_flags, self.isa_flags)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
@@ -109,15 +109,23 @@ impl TargetIsa for Isa {
         sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink, self)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink, self)
     }
+
+    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedLessThan
+    }
+
+    fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedGreaterThanOrEqual
+    }
 }
 
 impl fmt::Display for Isa {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}\n{}", self.shared_flags, self.isa_flags)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/isa/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/mod.rs
@@ -366,9 +366,15 @@ pub trait TargetIsa: fmt::Display + Sync
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
         sink: &mut dyn binemit::CodeSink,
     );
 
     /// Emit a whole function into memory.
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
+
+    /// IntCC condition for Unsigned Addition Overflow (Carry).
+    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC;
+
+    /// IntCC condition for Unsigned Subtraction Overflow (Borrow/Carry).
+    fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC;
 }
--- a/third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
@@ -116,16 +116,24 @@ impl TargetIsa for Isa {
         sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink, self)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink, self)
     }
+
+    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
+        unimplemented!()
+    }
+
+    fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
+        unimplemented!()
+    }
 }
 
 #[cfg(test)]
 mod tests {
     use crate::ir::{immediates, types};
     use crate::ir::{Function, InstructionData, Opcode};
     use crate::isa;
     use crate::settings::{self, Configurable};
--- a/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
@@ -267,18 +267,18 @@ fn sib<CS: CodeSink + ?Sized>(scale: u8,
 ///
 /// ---- 0x70: Short conditional branch.
 /// 0x0f 0x80: Long conditional branch.
 /// 0x0f 0x90: SetCC.
 ///
 fn icc2opc(cond: IntCC) -> u16 {
     use crate::ir::condcodes::IntCC::*;
     match cond {
-        // 0x0 = Overflow.
-        // 0x1 = !Overflow.
+        Overflow => 0x0,
+        NotOverflow => 0x1,
         UnsignedLessThan => 0x2,
         UnsignedGreaterThanOrEqual => 0x3,
         Equal => 0x4,
         NotEqual => 0x5,
         UnsignedLessThanOrEqual => 0x6,
         UnsignedGreaterThan => 0x7,
         // 0x8 = Sign.
         // 0x9 = !Sign.
--- a/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
@@ -401,22 +401,26 @@ fn expand_fcvt_from_uint(
         _ => panic!("Need fcvt_from_uint: {}", func.dfg.display_inst(inst, None)),
     }
     let xty = func.dfg.value_type(x);
     let result = func.dfg.first_result(inst);
     let ty = func.dfg.value_type(result);
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
-    // Conversion from unsigned 32-bit is easy on x86-64.
-    // TODO: This should be guarded by an ISA check.
-    if xty == ir::types::I32 {
-        let wide = pos.ins().uextend(ir::types::I64, x);
-        pos.func.dfg.replace(inst).fcvt_from_sint(ty, wide);
-        return;
+    // Conversion from an unsigned int smaller than 64bit is easy on x86-64.
+    match xty {
+        ir::types::I8 | ir::types::I16 | ir::types::I32 => {
+            // TODO: This should be guarded by an ISA check.
+            let wide = pos.ins().uextend(ir::types::I64, x);
+            pos.func.dfg.replace(inst).fcvt_from_sint(ty, wide);
+            return;
+        }
+        ir::types::I64 => {}
+        _ => unimplemented!(),
     }
 
     let old_ebb = pos.func.layout.pp_ebb(inst);
 
     // EBB handling the case where x >= 0.
     let poszero_ebb = pos.func.dfg.make_ebb();
 
     // EBB handling the case where x < 0.
@@ -890,16 +894,90 @@ fn expand_fcvt_to_uint_sat(
     cfg.recompute_ebb(pos.func, old_ebb);
     cfg.recompute_ebb(pos.func, below_pow2nm1_or_nan_ebb);
     cfg.recompute_ebb(pos.func, below_pow2nm1_ebb);
     cfg.recompute_ebb(pos.func, large);
     cfg.recompute_ebb(pos.func, uint_large_ebb);
     cfg.recompute_ebb(pos.func, done);
 }
 
+/// Convert shuffle instructions.
+fn convert_shuffle(
+    inst: ir::Inst,
+    func: &mut ir::Function,
+    _cfg: &mut ControlFlowGraph,
+    _isa: &dyn TargetIsa,
+) {
+    let mut pos = FuncCursor::new(func).at_inst(inst);
+    pos.use_srcloc(inst);
+
+    if let ir::InstructionData::Shuffle { args, mask, .. } = pos.func.dfg[inst] {
+        // A mask-building helper: in 128-bit SIMD, 0-15 indicate which lane to read from and a 1
+        // in the most significant position zeroes the lane.
+        let zero_unknown_lane_index = |b: u8| if b > 15 { 0b10000000 } else { b };
+
+        // We only have to worry about aliasing here because copies will be introduced later (in
+        // regalloc).
+        let a = pos.func.dfg.resolve_aliases(args[0]);
+        let b = pos.func.dfg.resolve_aliases(args[1]);
+        let mask = pos
+            .func
+            .dfg
+            .immediates
+            .get(mask)
+            .expect("The shuffle immediate should have been recorded before this point")
+            .clone();
+        if a == b {
+            // PSHUFB the first argument (since it is the same as the second).
+            let constructed_mask = mask
+                .iter()
+                // If the mask is greater than 15 it still may be referring to a lane in b.
+                .map(|&b| if b > 15 { b.wrapping_sub(16) } else { b })
+                .map(zero_unknown_lane_index)
+                .collect();
+            let handle = pos.func.dfg.constants.insert(constructed_mask);
+            // Move the built mask into another XMM register.
+            let a_type = pos.func.dfg.value_type(a);
+            let mask_value = pos.ins().vconst(a_type, handle);
+            // Shuffle the single incoming argument.
+            pos.func.dfg.replace(inst).x86_pshufb(a, mask_value);
+        } else {
+            // PSHUFB the first argument, placing zeroes for unused lanes.
+            let constructed_mask = mask.iter().cloned().map(zero_unknown_lane_index).collect();
+            let handle = pos.func.dfg.constants.insert(constructed_mask);
+            // Move the built mask into another XMM register.
+            let a_type = pos.func.dfg.value_type(a);
+            let mask_value = pos.ins().vconst(a_type, handle);
+            // Shuffle the first argument.
+            let shuffled_first_arg = pos.ins().x86_pshufb(a, mask_value);
+
+            // PSHUFB the second argument, placing zeroes for unused lanes.
+            let constructed_mask = mask
+                .iter()
+                .map(|b| b.wrapping_sub(16))
+                .map(zero_unknown_lane_index)
+                .collect();
+            let handle = pos.func.dfg.constants.insert(constructed_mask);
+            // Move the built mask into another XMM register.
+            let b_type = pos.func.dfg.value_type(b);
+            let mask_value = pos.ins().vconst(b_type, handle);
+            // Shuffle the second argument.
+            let shuffled_second_arg = pos.ins().x86_pshufb(b, mask_value);
+
+            // OR the vectors together to form the final shuffled value.
+            pos.func
+                .dfg
+                .replace(inst)
+                .bor(shuffled_first_arg, shuffled_second_arg);
+
+            // TODO when AVX512 is enabled we should replace this sequence with a single VPERMB
+        };
+    }
+}
+
 /// Because floats already exist in XMM registers, we can keep them there when executing a CLIF
 /// extractlane instruction
 fn convert_extractlane(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
     _isa: &dyn TargetIsa,
 ) {
--- a/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
@@ -137,15 +137,23 @@ impl TargetIsa for Isa {
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink, self)
     }
 
     fn prologue_epilogue(&self, func: &mut ir::Function) -> CodegenResult<()> {
         let _tt = timing::prologue_epilogue();
         abi::prologue_epilogue(func, self)
     }
+
+    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedLessThan
+    }
+
+    fn unsigned_sub_overflow_condition(&self) -> ir::condcodes::IntCC {
+        ir::condcodes::IntCC::UnsignedLessThan
+    }
 }
 
 impl fmt::Display for Isa {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}\n{}", self.shared_flags, self.isa_flags)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/legalizer/heap.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/heap.rs
@@ -78,17 +78,21 @@ fn dynamic_addr(
         let adj_bound = pos.ins().iadd_imm(bound, -(access_size as i64));
         oob = pos
             .ins()
             .icmp(IntCC::UnsignedGreaterThan, offset, adj_bound);
     } else {
         // We need an overflow check for the adjusted offset.
         let access_size_val = pos.ins().iconst(offset_ty, access_size as i64);
         let (adj_offset, overflow) = pos.ins().iadd_ifcout(offset, access_size_val);
-        pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
+        pos.ins().trapif(
+            isa.unsigned_add_overflow_condition(),
+            overflow,
+            ir::TrapCode::HeapOutOfBounds,
+        );
         oob = pos
             .ins()
             .icmp(IntCC::UnsignedGreaterThan, adj_offset, bound);
     }
     pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
 
     compute_addr(isa, inst, heap, addr_ty, offset, offset_ty, pos.func);
 }
--- a/third_party/rust/cranelift-codegen/src/lib.rs
+++ b/third_party/rust/cranelift-codegen/src/lib.rs
@@ -90,17 +90,16 @@ mod fx;
 mod iterators;
 mod legalizer;
 mod licm;
 mod nan_canonicalization;
 mod partition_slice;
 mod postopt;
 mod predicates;
 mod redundant_reload_remover;
-mod ref_slice;
 mod regalloc;
 mod result;
 mod scoped_hash_map;
 mod simple_gvn;
 mod simple_preopt;
 mod stack_layout;
 mod topo_order;
 mod unreachable_code;
--- a/third_party/rust/cranelift-codegen/src/predicates.rs
+++ b/third_party/rust/cranelift-codegen/src/predicates.rs
@@ -26,16 +26,28 @@ pub fn is_zero_64_bit_float<T: Into<ir::
 
 /// Check that a 32-bit floating point value is zero.
 #[allow(dead_code)]
 pub fn is_zero_32_bit_float<T: Into<ir::immediates::Ieee32>>(x: T) -> bool {
     let x32 = x.into();
     x32.bits() == 0
 }
 
+/// Check that a 128-bit vector contains all zeroes.
+#[allow(dead_code)]
+pub fn is_all_zeroes_128_bit<'b, T: PartialEq<&'b [u8; 16]>>(x: T) -> bool {
+    x.eq(&&[0; 16])
+}
+
+/// Check that a 128-bit vector contains all ones.
+#[allow(dead_code)]
+pub fn is_all_ones_128_bit<'b, T: PartialEq<&'b [u8; 16]>>(x: T) -> bool {
+    x.eq(&&[0xff; 16])
+}
+
 /// Check that `x` is the same as `y`.
 #[allow(dead_code)]
 pub fn is_equal<T: Eq + Copy, O: Into<T> + Copy>(x: T, y: O) -> bool {
     x == y.into()
 }
 
 /// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.
 #[allow(dead_code)]
@@ -104,9 +116,24 @@ mod tests {
         let x1 = Imm64::new(-8);
         let x2 = Imm64::new(8);
 
         assert!(is_signed_int(x1, 16, 2));
         assert!(is_signed_int(x2, 16, 2));
         assert!(!is_signed_int(x1, 16, 4));
         assert!(!is_signed_int(x2, 16, 4));
     }
+
+    #[test]
+    fn is_all_zeroes() {
+        assert!(is_all_zeroes_128_bit(&[0; 16]));
+        assert!(is_all_zeroes_128_bit(vec![
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        ]));
+        assert!(!is_all_zeroes_128_bit(&[1; 16]));
+    }
+
+    #[test]
+    fn is_all_ones() {
+        assert!(!is_all_ones_128_bit(&[0; 16]));
+        assert!(is_all_ones_128_bit(&[0xff; 16]));
+    }
 }
deleted file mode 100644
--- a/third_party/rust/cranelift-codegen/src/ref_slice.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Functions for converting a reference into a singleton slice.
-//!
-//! See also the [`ref_slice` crate](https://crates.io/crates/ref_slice).
-//!
-//! We define the functions here to avoid external dependencies, and to ensure that they are
-//! inlined in this crate.
-//!
-//! Despite their using an unsafe block, these functions are completely safe.
-
-use core::slice;
-
-pub fn ref_slice<T>(s: &T) -> &[T] {
-    unsafe { slice::from_raw_parts(s, 1) }
-}
-
-pub fn ref_slice_mut<T>(s: &mut T) -> &mut [T] {
-    unsafe { slice::from_raw_parts_mut(s, 1) }
-}
--- a/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
@@ -194,17 +194,18 @@ impl<'a> Context<'a> {
 
             // Now `pred_inst` is known to be a back-edge, so it is possible for parameter values
             // to be live at the use.
             for i in 0..num_params {
                 let param = self.func.dfg.ebb_params(ebb)[i];
                 if self.liveness[param].reaches_use(
                     pred_inst,
                     pred_ebb,
-                    self.liveness.context(&self.func.layout),
+                    self.liveness.forest(),
+                    &self.func.layout,
                 ) {
                     self.isolate_param(ebb, param);
                 }
             }
         }
     }
 
     // Union EBB parameter value `num` with the corresponding EBB arguments on the predecessor
@@ -235,32 +236,31 @@ impl<'a> Context<'a> {
                     continue;
                 }
             }
 
             // Check for basic interference: If `arg` overlaps a value defined at the entry to
             // `ebb`, it can never be used as an EBB argument.
             let interference = {
                 let lr = &self.liveness[arg];
-                let ctx = self.liveness.context(&self.func.layout);
 
                 // There are two ways the argument value can interfere with `ebb`:
                 //
                 // 1. It is defined in a dominating EBB and live-in to `ebb`.
                 // 2. If is itself a parameter value for `ebb`. This case should already have been
                 //    eliminated by `isolate_conflicting_params()`.
                 debug_assert!(
                     lr.def() != ebb.into(),
                     "{} parameter {} was missed by isolate_conflicting_params()",
                     ebb,
                     arg
                 );
 
                 // The only other possibility is that `arg` is live-in to `ebb`.
-                lr.is_livein(ebb, ctx)
+                lr.is_livein(ebb, self.liveness.forest(), &self.func.layout)
             };
 
             if interference {
                 let new_arg = self.isolate_arg(pred_ebb, pred_inst, argnum, arg);
                 self.virtregs.union(param, new_arg);
             } else {
                 self.virtregs.union(param, arg);
             }
@@ -430,18 +430,22 @@ impl<'a> Context<'a> {
                 .push_node(node, self.func, self.domtree, self.preorder)
             {
                 None => continue,
                 Some(n) => n,
             };
 
             // Check for interference between `parent` and `value`. Since `parent` dominates
             // `value`, we only have to check if it overlaps the definition.
-            let ctx = self.liveness.context(&self.func.layout);
-            if self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx) {
+            if self.liveness[parent.value].overlaps_def(
+                node.def,
+                node.ebb,
+                self.liveness.forest(),
+                &self.func.layout,
+            ) {
                 // The two values are interfering, so they can't be in the same virtual register.
                 debug!("-> interference: {} overlaps def of {}", parent, value);
                 return false;
             }
         }
 
         // No interference found.
         true
@@ -588,17 +592,16 @@ impl<'a> Context<'a> {
             ),
             self.vcopies.iter(func),
         );
 
         // Now push the values in order to the dominator forest.
         // This gives us the closest dominating value def for each of the values.
         self.forest.clear();
         self.values.clear();
-        let ctx = self.liveness.context(&self.func.layout);
         for node in nodes {
             // Accumulate ordered values for the new vreg.
             if node.is_value() {
                 self.values.push(node.value);
             }
 
             // Push this value and get the nearest dominating def back.
             let parent = match self.forest.push_node(node, func, domtree, preorder) {
@@ -618,17 +621,22 @@ impl<'a> Context<'a> {
                 if parent.is_vcopy || node.value == parent.value {
                     self.forest.pop_last();
                     continue;
                 }
 
                 // Check if the parent value interferes with the virtual copy.
                 let inst = node.def.unwrap_inst();
                 if node.set_id != parent.set_id
-                    && self.liveness[parent.value].reaches_use(inst, node.ebb, ctx)
+                    && self.liveness[parent.value].reaches_use(
+                        inst,
+                        node.ebb,
+                        self.liveness.forest(),
+                        &self.func.layout,
+                    )
                 {
                     debug!(
                         " - interference: {} overlaps vcopy at {}:{}",
                         parent,
                         node.ebb,
                         self.func.dfg.display_inst(inst, self.isa)
                     );
                     return false;
@@ -642,17 +650,22 @@ impl<'a> Context<'a> {
             // avoid an interference check against a value higher up.
             if parent.is_vcopy {
                 continue;
             }
 
             // Both node and parent are values, so check for interference.
             debug_assert!(node.is_value() && parent.is_value());
             if node.set_id != parent.set_id
-                && self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx)
+                && self.liveness[parent.value].overlaps_def(
+                    node.def,
+                    node.ebb,
+                    self.liveness.forest(),
+                    &self.func.layout,
+                )
             {
                 // The two values are interfering.
                 debug!(" - interference: {} overlaps def of {}", parent, node.value);
                 return false;
             }
         }
 
         // The values vector should receive all values.
--- a/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
@@ -49,17 +49,17 @@ use crate::ir::{ArgumentLoc, InstBuilder
 use crate::ir::{Ebb, Function, Inst, InstructionData, Layout, Opcode, SigRef, Value, ValueLoc};
 use crate::isa::{regs_overlap, RegClass, RegInfo, RegUnit};
 use crate::isa::{ConstraintKind, EncInfo, OperandConstraint, RecipeConstraints, TargetIsa};
 use crate::packed_option::PackedOption;
 use crate::regalloc::affinity::Affinity;
 use crate::regalloc::diversion::RegDiversions;
 use crate::regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
 use crate::regalloc::liveness::Liveness;
-use crate::regalloc::liverange::{LiveRange, LiveRangeContext};
+use crate::regalloc::liverange::{LiveRange, LiveRangeForest};
 use crate::regalloc::register_set::RegisterSet;
 use crate::regalloc::solver::{Solver, SolverError};
 use crate::timing;
 use core::mem;
 use log::debug;
 
 /// Data structures for the coloring pass.
 ///
@@ -456,17 +456,17 @@ impl<'a> Context<'a> {
                 // This is a multi-way branch like `br_table`. We only support arguments on
                 // single-destination branches.
                 debug_assert_eq!(
                     self.cur.func.dfg.inst_variable_args(inst).len(),
                     0,
                     "Can't handle EBB arguments: {}",
                     self.cur.display_inst(inst)
                 );
-                self.undivert_regs(|lr, _| !lr.is_local());
+                self.undivert_regs(|lr, _, _| !lr.is_local());
             }
         }
 
         if self.solver.has_fixed_input_conflicts() {
             self.divert_fixed_input_conflicts(tracker.live());
         }
 
         self.solver.inputs_done();
@@ -720,18 +720,23 @@ impl<'a> Context<'a> {
                     let cur_reg = self.divert.reg(value, &self.cur.func.locations);
 
                     // This is the opposite condition of `program_input_constraints()`. The pinned
                     // register mustn't be added back as a variable.
                     if op.regclass.contains(cur_reg) && !self.is_pinned_reg(op.regclass, cur_reg) {
                         // This code runs after calling `solver.inputs_done()` so we must identify
                         // the new variable as killed or live-through. Always special-case the
                         // pinned register as a through variable.
-                        let ctx = self.liveness.context(&self.cur.func.layout);
-                        if self.liveness[value].killed_at(inst, ctx.order.pp_ebb(inst), ctx) {
+                        let layout = &self.cur.func.layout;
+                        if self.liveness[value].killed_at(
+                            inst,
+                            layout.pp_ebb(inst),
+                            self.liveness.forest(),
+                            layout,
+                        ) {
                             self.solver.add_killed_var(value, op.regclass, cur_reg);
                         } else {
                             self.solver.add_through_var(value, op.regclass, cur_reg);
                         }
                     }
                 }
                 ConstraintKind::FixedReg(_)
                 | ConstraintKind::FixedTied(_)
@@ -750,17 +755,17 @@ impl<'a> Context<'a> {
     /// Returns true if this is the first time a branch to `dest` is seen, so the `dest` argument
     /// values should be colored after `shuffle_inputs`.
     fn program_ebb_arguments(&mut self, inst: Inst, dest: Ebb) -> bool {
         // Find diverted registers that are live-in to `dest` and reassign them to their global
         // home.
         //
         // Values with a global live range that are not live in to `dest` could appear as branch
         // arguments, so they can't always be un-diverted.
-        self.undivert_regs(|lr, ctx| lr.is_livein(dest, ctx));
+        self.undivert_regs(|lr, forest, layout| lr.is_livein(dest, forest, layout));
 
         // Now handle the EBB arguments.
         let br_args = self.cur.func.dfg.inst_variable_args(inst);
         let dest_args = self.cur.func.dfg.ebb_params(dest);
         debug_assert_eq!(br_args.len(), dest_args.len());
         for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) {
             // The first time we encounter a branch to `dest`, we get to pick the location. The
             // following times we see a branch to `dest`, we must follow suit.
@@ -820,24 +825,24 @@ impl<'a> Context<'a> {
             }
         }
     }
 
     /// Find all diverted registers where `pred` returns `true` and undo their diversion so they
     /// are reallocated to their global register assignments.
     fn undivert_regs<Pred>(&mut self, mut pred: Pred)
     where
-        Pred: FnMut(&LiveRange, LiveRangeContext<Layout>) -> bool,
+        Pred: FnMut(&LiveRange, &LiveRangeForest, &Layout) -> bool,
     {
         for (&value, rdiv) in self.divert.iter() {
             let lr = self
                 .liveness
                 .get(value)
                 .expect("Missing live range for diverted register");
-            if pred(lr, self.liveness.context(&self.cur.func.layout)) {
+            if pred(lr, self.liveness.forest(), &self.cur.func.layout) {
                 if let Affinity::Reg(rci) = lr.affinity {
                     let rc = self.reginfo.rc(rci);
                     // Stack diversions should not be possible here. They only live transiently
                     // during `shuffle_inputs()`.
                     self.solver.reassign_in(
                         value,
                         rc,
                         rdiv.to.unwrap_reg(),
@@ -1075,30 +1080,31 @@ impl<'a> Context<'a> {
     ///
     /// This means that the current instruction is a branch and `value` is live in to one of the
     /// branch destinations. Branch arguments and EBB parameters are not considered live on the
     /// edge.
     fn is_live_on_outgoing_edge(&self, value: Value) -> bool {
         use crate::ir::instructions::BranchInfo::*;
 
         let inst = self.cur.current_inst().expect("Not on an instruction");
-        let ctx = self.liveness.context(&self.cur.func.layout);
+        let layout = &self.cur.func.layout;
+        let forest = self.liveness.forest();
         match self.cur.func.dfg.analyze_branch(inst) {
             NotABranch => false,
             SingleDest(ebb, _) => {
                 let lr = &self.liveness[value];
-                lr.is_livein(ebb, ctx)
+                lr.is_livein(ebb, forest, layout)
             }
             Table(jt, ebb) => {
                 let lr = &self.liveness[value];
                 !lr.is_local()
-                    && (ebb.map_or(false, |ebb| lr.is_livein(ebb, ctx))
+                    && (ebb.map_or(false, |ebb| lr.is_livein(ebb, forest, layout))
                         || self.cur.func.jump_tables[jt]
                             .iter()
-                            .any(|ebb| lr.is_livein(*ebb, ctx)))
+                            .any(|ebb| lr.is_livein(*ebb, forest, layout)))
             }
         }
     }
 
     /// Emit `regmove` instructions as needed to move the live registers into place before the
     /// instruction. Also update `self.divert` accordingly.
     ///
     /// The `self.cur` cursor is expected to point at the instruction. The register moves are
--- a/third_party/rust/cranelift-codegen/src/regalloc/live_value_tracker.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/live_value_tracker.rs
@@ -186,25 +186,24 @@ impl LiveValueTracker {
         if let Some(idom) = domtree.idom(ebb) {
             // If the immediate dominator exits, we must have a stored list for it. This is a
             // requirement to the order EBBs are visited: All dominators must have been processed
             // before the current EBB.
             let idom_live_list = self
                 .idom_sets
                 .get(&idom)
                 .expect("No stored live set for dominator");
-            let ctx = liveness.context(layout);
             // Get just the values that are live-in to `ebb`.
             for &value in idom_live_list.as_slice(&self.idom_pool) {
                 let lr = liveness
                     .get(value)
                     .expect("Immediate dominator value has no live range");
 
                 // Check if this value is live-in here.
-                if let Some(endpoint) = lr.livein_local_end(ebb, ctx) {
+                if let Some(endpoint) = lr.livein_local_end(ebb, liveness.forest(), layout) {
                     self.live.push(value, endpoint, lr);
                 }
             }
         }
 
         // Now add all the live parameters to `ebb`.
         let first_arg = self.live.values.len();
         for &value in dfg.ebb_params(ebb) {
--- a/third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
@@ -176,17 +176,17 @@
 //! There is some room for improvement.
 
 use crate::entity::SparseMap;
 use crate::flowgraph::{BasicBlock, ControlFlowGraph};
 use crate::ir::dfg::ValueDef;
 use crate::ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value};
 use crate::isa::{EncInfo, OperandConstraint, TargetIsa};
 use crate::regalloc::affinity::Affinity;
-use crate::regalloc::liverange::{LiveRange, LiveRangeContext, LiveRangeForest};
+use crate::regalloc::liverange::{LiveRange, LiveRangeForest};
 use crate::timing;
 use core::mem;
 use core::ops::Index;
 use std::vec::Vec;
 
 /// A set of live ranges, indexed by value number.
 type LiveRangeSet = SparseMap<Value, LiveRange>;
 
@@ -309,26 +309,26 @@ impl Liveness {
     pub fn new() -> Self {
         Self {
             ranges: LiveRangeSet::new(),
             forest: LiveRangeForest::new(),
             worklist: Vec::new(),
         }
     }
 
+    /// Current forest storage.
+    pub fn forest(&self) -> &LiveRangeForest {
+        &self.forest
+    }
+
     /// Current live ranges.
     pub fn ranges(&self) -> &LiveRangeSet {
         &self.ranges
     }
 
-    /// Get a context needed for working with a `LiveRange`.
-    pub fn context<'a>(&'a self, layout: &'a Layout) -> LiveRangeContext<'a, Layout> {
-        LiveRangeContext::new(layout, &self.forest)
-    }
-
     /// Clear all data structures in this liveness analysis.
     pub fn clear(&mut self) {
         self.ranges.clear();
         self.forest.clear();
         self.worklist.clear();
     }
 
     /// Get the live range for `value`, if it exists.
--- a/third_party/rust/cranelift-codegen/src/regalloc/liverange.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/liverange.rs
@@ -53,18 +53,26 @@
 //! - `i1-i2` and `i2-i2` don't interfere.
 //! - `i2-i3` and `i2-i2` do interfere.
 //!
 //! Because of this behavior around interval end points, live range interference is not completely
 //! equivalent to mathematical intersection of open or half-open intervals.
 //!
 //! # Implementation notes
 //!
-//! A few notes about the implementation of this data structure. This should not concern someone
-//! only looking to use the public interface.
+//! A few notes about the implementation of the live intervals field `liveins`. This should not
+//! concern someone only looking to use the public interface.
+//!
+//! ## Current representation
+//!
+//! Our current implementation uses a B-tree map with the necessary interface for an efficient
+//! implementation of coalescing, implemented as a generic data-structure bforest::Map.
+//!
+//! A `BTreeMap<Ebb, Inst>` could have been used for the live-in intervals, but it doesn't provide
+//! the necessary API to make coalescing easy, nor does it optimize for our types' sizes.
 //!
 //! ## EBB ordering
 //!
 //! The relative order of EBBs is used to maintain a sorted list of live-in intervals and to
 //! coalesce adjacent live-in intervals when the prior interval covers the whole EBB. This doesn't
 //! depend on any property of the program order, so alternative orderings are possible:
 //!
 //! 1. The EBB layout order. This is what we currently use.
@@ -94,23 +102,16 @@
 //! EBBs. We can represent that by switching to a sorted `Vec<ProgramPoint>` representation where
 //! an `[Ebb, Inst]` pair represents a coalesced range, while an `Inst` entry without a preceding
 //! `Ebb` entry represents a single live-in interval.
 //!
 //! This representation is more compact for a live range with many uncoalesced live-in intervals.
 //! It is more complicated to work with, though, so it is probably not worth it. The performance
 //! benefits of switching to a numerical EBB order only appears if the binary search is doing
 //! EBB-EBB comparisons.
-//!
-//! ## B-tree representation
-//!
-//! A `BTreeMap<Ebb, Inst>` could also be used for the live-in intervals. It looks like the
-//! standard library B-tree doesn't provide the necessary interface for an efficient implementation
-//! of coalescing, so we would need to roll our own.
-//!
 
 use crate::bforest;
 use crate::entity::SparseMapValue;
 use crate::ir::{Ebb, ExpandedProgramPoint, Inst, Layout, ProgramOrder, ProgramPoint, Value};
 use crate::regalloc::affinity::Affinity;
 use core::cmp::Ordering;
 use core::marker::PhantomData;
 
@@ -136,23 +137,23 @@ use core::marker::PhantomData;
 /// ordering take an explicit `ProgramOrder` object, and it is the caller's responsibility to
 /// ensure that the provided ordering is consistent between calls.
 ///
 /// In particular, changing the order of EBBs or inserting new EBBs will invalidate live ranges.
 ///
 /// Inserting new instructions in the layout is safe, but removing instructions is not. Besides the
 /// instructions using or defining their value, `LiveRange` structs can contain references to
 /// branch and jump instructions.
-pub type LiveRange = GenLiveRange<Layout>;
+pub type LiveRange = GenericLiveRange<Layout>;
 
 /// Generic live range implementation.
 ///
 /// The intended generic parameter is `PO=Layout`, but tests are simpler with a mock order.
 /// Use `LiveRange` instead of using this generic directly.
-pub struct GenLiveRange<PO: ProgramOrder> {
+pub struct GenericLiveRange<PO: ProgramOrder> {
     /// The value described by this live range.
     /// This member can't be modified in case the live range is stored in a `SparseMap`.
     value: Value,
 
     /// The preferred register allocation for this value.
     pub affinity: Affinity,
 
     /// The instruction or EBB header where this value is defined.
@@ -173,54 +174,44 @@ pub struct GenLiveRange<PO: ProgramOrder
     ///
     /// The entries are non-overlapping, and none of them overlap the EBB where the value is
     /// defined.
     liveins: bforest::Map<Ebb, Inst>,
 
     po: PhantomData<*const PO>,
 }
 
-/// Context information needed to query a `LiveRange`.
-pub struct LiveRangeContext<'a, PO: 'a + ProgramOrder> {
-    /// Ordering of EBBs.
-    pub order: &'a PO,
-    /// Memory pool.
-    pub forest: &'a bforest::MapForest<Ebb, Inst>,
-}
-
-impl<'a, PO: ProgramOrder> LiveRangeContext<'a, PO> {
-    /// Make a new context.
-    pub fn new(order: &'a PO, forest: &'a bforest::MapForest<Ebb, Inst>) -> Self {
-        Self { order, forest }
-    }
-}
-
-impl<'a, PO: ProgramOrder> Clone for LiveRangeContext<'a, PO> {
-    fn clone(&self) -> Self {
-        LiveRangeContext {
-            order: self.order,
-            forest: self.forest,
-        }
-    }
-}
-
-impl<'a, PO: ProgramOrder> Copy for LiveRangeContext<'a, PO> {}
-
 /// Forest of B-trees used for storing live ranges.
 pub type LiveRangeForest = bforest::MapForest<Ebb, Inst>;
 
 struct Cmp<'a, PO: ProgramOrder + 'a>(&'a PO);
 
 impl<'a, PO: ProgramOrder> bforest::Comparator<Ebb> for Cmp<'a, PO> {
     fn cmp(&self, a: Ebb, b: Ebb) -> Ordering {
         self.0.cmp(a, b)
     }
 }
 
-impl<PO: ProgramOrder> GenLiveRange<PO> {
+/// A simple helper macro to make comparisons more natural to read.
+macro_rules! cmp {
+    ($order:ident, $a:ident > $b:expr) => {
+        $order.cmp($a, $b) == Ordering::Greater
+    };
+    ($order:ident, $a:ident >= $b:expr) => {
+        $order.cmp($a, $b) != Ordering::Less
+    };
+    ($order:ident, $a:ident < $b:expr) => {
+        $order.cmp($a, $b) == Ordering::Less
+    };
+    ($order:ident, $a:ident <= $b:expr) => {
+        $order.cmp($a, $b) != Ordering::Greater
+    };
+}
+
+impl<PO: ProgramOrder> GenericLiveRange<PO> {
     /// Create a new live range for `value` defined at `def`.
     ///
     /// The live range will be created as dead, but it can be extended with `extend_in_ebb()`.
     pub fn new(value: Value, def: ProgramPoint, affinity: Affinity) -> Self {
         Self {
             value,
             affinity,
             def_begin: def,
@@ -247,50 +238,48 @@ impl<PO: ProgramOrder> GenLiveRange<PO> 
         to: Inst,
         order: &PO,
         forest: &mut bforest::MapForest<Ebb, Inst>,
     ) -> bool {
         // First check if we're extending the def interval.
         //
         // We're assuming here that `to` never precedes `def_begin` in the same EBB, but we can't
         // check it without a method for getting `to`'s EBB.
-        if order.cmp(ebb, self.def_end) != Ordering::Greater
-            && order.cmp(to, self.def_begin) != Ordering::Less
-        {
+        if cmp!(order, ebb <= self.def_end) && cmp!(order, to >= self.def_begin) {
             let to_pp = to.into();
             debug_assert_ne!(
                 to_pp, self.def_begin,
                 "Can't use value in the defining instruction."
             );
-            if order.cmp(to, self.def_end) == Ordering::Greater {
+            if cmp!(order, to > self.def_end) {
                 self.def_end = to_pp;
             }
             return false;
         }
 
         // Now check if we're extending any of the existing live-in intervals.
         let cmp = Cmp(order);
         let mut c = self.liveins.cursor(forest, &cmp);
         let first_time_livein;
 
         if let Some(end) = c.goto(ebb) {
             // There's an interval beginning at `ebb`. See if it extends.
             first_time_livein = false;
-            if order.cmp(end, to) == Ordering::Less {
+            if cmp!(order, end < to) {
                 *c.value_mut().unwrap() = to;
             } else {
                 return first_time_livein;
             }
         } else if let Some((_, end)) = c.prev() {
             // There's no interval beginning at `ebb`, but we could still be live-in at `ebb` with
             // a coalesced interval that begins before and ends after.
-            if order.cmp(end, ebb) == Ordering::Greater {
+            if cmp!(order, end > ebb) {
                 // Yep, the previous interval overlaps `ebb`.
                 first_time_livein = false;
-                if order.cmp(end, to) == Ordering::Less {
+                if cmp!(order, end < to) {
                     *c.value_mut().unwrap() = to;
                 } else {
                     return first_time_livein;
                 }
             } else {
                 first_time_livein = true;
                 // The current interval does not overlap `ebb`, but it may still be possible to
                 // coalesce with it.
@@ -301,17 +290,17 @@ impl<PO: ProgramOrder> GenLiveRange<PO> 
                 }
             }
         } else {
             // There is no existing interval before `ebb`.
             first_time_livein = true;
             c.insert(ebb, to);
         }
 
-        // Now `c` to left pointing at an interval that ends in `to`.
+        // Now `c` is left pointing at an interval that ends in `to`.
         debug_assert_eq!(c.value(), Some(to));
 
         // See if it can be coalesced with the following interval.
         if let Some((next_ebb, next_end)) = c.next() {
             if order.is_ebb_gap(to, next_ebb) {
                 // Remove this interval and extend the previous end point to `next_end`.
                 c.remove();
                 c.prev();
@@ -365,103 +354,101 @@ impl<PO: ProgramOrder> GenLiveRange<PO> 
     /// Get the local end-point of this live range in an EBB where it is live-in.
     ///
     /// If this live range is not live-in to `ebb`, return `None`. Otherwise, return the end-point
     /// of this live range's local interval in `ebb`.
     ///
     /// If the live range is live through all of `ebb`, the terminator of `ebb` is a correct
     /// answer, but it is also possible that an even later program point is returned. So don't
     /// depend on the returned `Inst` to belong to `ebb`.
-    pub fn livein_local_end(&self, ebb: Ebb, ctx: LiveRangeContext<PO>) -> Option<Inst> {
-        let cmp = Cmp(ctx.order);
+    pub fn livein_local_end(&self, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> Option<Inst> {
+        let cmp = Cmp(order);
         self.liveins
-            .get_or_less(ebb, ctx.forest, &cmp)
+            .get_or_less(ebb, forest, &cmp)
             .and_then(|(_, inst)| {
                 // We have an entry that ends at `inst`.
-                if ctx.order.cmp(inst, ebb) == Ordering::Greater {
+                if cmp!(order, inst > ebb) {
                     Some(inst)
                 } else {
                     None
                 }
             })
     }
 
     /// Is this value live-in to `ebb`?
     ///
     /// An EBB argument is not considered to be live in.
-    pub fn is_livein(&self, ebb: Ebb, ctx: LiveRangeContext<PO>) -> bool {
-        self.livein_local_end(ebb, ctx).is_some()
+    pub fn is_livein(&self, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool {
+        self.livein_local_end(ebb, forest, order).is_some()
     }
 
     /// Get all the live-in intervals.
     ///
     /// Note that the intervals are stored in a compressed form so each entry may span multiple
     /// EBBs where the value is live in.
-    pub fn liveins<'a>(&'a self, ctx: LiveRangeContext<'a, PO>) -> bforest::MapIter<'a, Ebb, Inst> {
-        self.liveins.iter(ctx.forest)
+    pub fn liveins<'a>(&'a self, forest: &'a LiveRangeForest) -> bforest::MapIter<'a, Ebb, Inst> {
+        self.liveins.iter(forest)
     }
 
     /// Check if this live range overlaps a definition in `ebb`.
     pub fn overlaps_def(
         &self,
         def: ExpandedProgramPoint,
         ebb: Ebb,
-        ctx: LiveRangeContext<PO>,
+        forest: &LiveRangeForest,
+        order: &PO,
     ) -> bool {
         // Two defs at the same program point always overlap, even if one is dead.
         if def == self.def_begin.into() {
             return true;
         }
 
         // Check for an overlap with the local range.
-        if ctx.order.cmp(def, self.def_begin) != Ordering::Less
-            && ctx.order.cmp(def, self.def_end) == Ordering::Less
-        {
+        if cmp!(order, def >= self.def_begin) && cmp!(order, def < self.def_end) {
             return true;
         }
 
         // Check for an overlap with a live-in range.
-        match self.livein_local_end(ebb, ctx) {
-            Some(inst) => ctx.order.cmp(def, inst) == Ordering::Less,
+        match self.livein_local_end(ebb, forest, order) {
+            Some(inst) => cmp!(order, def < inst),
             None => false,
         }
     }
 
     /// Check if this live range reaches a use at `user` in `ebb`.
-    pub fn reaches_use(&self, user: Inst, ebb: Ebb, ctx: LiveRangeContext<PO>) -> bool {
+    pub fn reaches_use(&self, user: Inst, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool {
         // Check for an overlap with the local range.
-        if ctx.order.cmp(user, self.def_begin) == Ordering::Greater
-            && ctx.order.cmp(user, self.def_end) != Ordering::Greater
-        {
+        if cmp!(order, user > self.def_begin) && cmp!(order, user <= self.def_end) {
             return true;
         }
 
         // Check for an overlap with a live-in range.
-        match self.livein_local_end(ebb, ctx) {
-            Some(inst) => ctx.order.cmp(user, inst) != Ordering::Greater,
+        match self.livein_local_end(ebb, forest, order) {
+            Some(inst) => cmp!(order, user <= inst),
             None => false,
         }
     }
 
     /// Check if this live range is killed at `user` in `ebb`.
-    pub fn killed_at(&self, user: Inst, ebb: Ebb, ctx: LiveRangeContext<PO>) -> bool {
-        self.def_local_end() == user.into() || self.livein_local_end(ebb, ctx) == Some(user)
+    pub fn killed_at(&self, user: Inst, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool {
+        self.def_local_end() == user.into()
+            || self.livein_local_end(ebb, forest, order) == Some(user)
     }
 }
 
 /// Allow a `LiveRange` to be stored in a `SparseMap` indexed by values.
-impl<PO: ProgramOrder> SparseMapValue<Value> for GenLiveRange<PO> {
+impl<PO: ProgramOrder> SparseMapValue<Value> for GenericLiveRange<PO> {
     fn key(&self) -> Value {
         self.value
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::{GenLiveRange, LiveRangeContext};
+    use super::GenericLiveRange;
     use crate::bforest;
     use crate::entity::EntityRef;
     use crate::ir::{Ebb, Inst, Value};
     use crate::ir::{ExpandedProgramPoint, ProgramOrder};
     use core::cmp::Ordering;
     use std::vec::Vec;
 
     // Dummy program order which simply compares indexes.
@@ -504,17 +491,21 @@ mod tests {
         fn pp_ebb<PP: Into<ExpandedProgramPoint>>(&self, pp: PP) -> Ebb {
             match pp.into() {
                 ExpandedProgramPoint::Inst(i) => self.inst_ebb(i),
                 ExpandedProgramPoint::Ebb(e) => e,
             }
         }
 
         // Validate the live range invariants.
-        fn validate(&self, lr: &GenLiveRange<ProgOrder>, forest: &bforest::MapForest<Ebb, Inst>) {
+        fn validate(
+            &self,
+            lr: &GenericLiveRange<ProgOrder>,
+            forest: &bforest::MapForest<Ebb, Inst>,
+        ) {
             // The def interval must cover a single EBB.
             let def_ebb = self.pp_ebb(lr.def_begin);
             assert_eq!(def_ebb, self.pp_ebb(lr.def_end));
 
             // Check that the def interval isn't backwards.
             match self.cmp(lr.def_begin, lr.def_end) {
                 Ordering::Equal => assert!(lr.liveins.is_empty()),
                 Ordering::Greater => {
@@ -548,56 +539,54 @@ mod tests {
 
     #[test]
     fn dead_def_range() {
         let v0 = Value::new(0);
         let e0 = Ebb::new(0);
         let i1 = Inst::new(1);
         let i2 = Inst::new(2);
         let e2 = Ebb::new(2);
-        let lr = GenLiveRange::new(v0, i1.into(), Default::default());
+        let lr = GenericLiveRange::new(v0, i1.into(), Default::default());
         let forest = &bforest::MapForest::new();
-        let ctx = LiveRangeContext::new(PO, forest);
         assert!(lr.is_dead());
         assert!(lr.is_local());
         assert_eq!(lr.def(), i1.into());
         assert_eq!(lr.def_local_end(), i1.into());
-        assert_eq!(lr.livein_local_end(e2, ctx), None);
-        PO.validate(&lr, ctx.forest);
+        assert_eq!(lr.livein_local_end(e2, forest, PO), None);
+        PO.validate(&lr, forest);
 
         // A dead live range overlaps its own def program point.
-        assert!(lr.overlaps_def(i1.into(), e0, ctx));
-        assert!(!lr.overlaps_def(i2.into(), e0, ctx));
-        assert!(!lr.overlaps_def(e0.into(), e0, ctx));
+        assert!(lr.overlaps_def(i1.into(), e0, forest, PO));
+        assert!(!lr.overlaps_def(i2.into(), e0, forest, PO));
+        assert!(!lr.overlaps_def(e0.into(), e0, forest, PO));
     }
 
     #[test]
     fn dead_arg_range() {
         let v0 = Value::new(0);
         let e2 = Ebb::new(2);
-        let lr = GenLiveRange::new(v0, e2.into(), Default::default());
+        let lr = GenericLiveRange::new(v0, e2.into(), Default::default());
         let forest = &bforest::MapForest::new();
-        let ctx = LiveRangeContext::new(PO, forest);
         assert!(lr.is_dead());
         assert!(lr.is_local());
         assert_eq!(lr.def(), e2.into());
         assert_eq!(lr.def_local_end(), e2.into());
         // The def interval of an EBB argument does not count as live-in.
-        assert_eq!(lr.livein_local_end(e2, ctx), None);
-        PO.validate(&lr, ctx.forest);
+        assert_eq!(lr.livein_local_end(e2, forest, PO), None);
+        PO.validate(&lr, forest);
     }
 
     #[test]
     fn local_def() {
         let v0 = Value::new(0);
         let e10 = Ebb::new(10);
         let i11 = Inst::new(11);
         let i12 = Inst::new(12);
         let i13 = Inst::new(13);
-        let mut lr = GenLiveRange::new(v0, i11.into(), Default::default());
+        let mut lr = GenericLiveRange::new(v0, i11.into(), Default::default());
         let forest = &mut bforest::MapForest::new();
 
         assert_eq!(lr.extend_in_ebb(e10, i13, PO, forest), false);
         PO.validate(&lr, forest);
         assert!(!lr.is_dead());
         assert!(lr.is_local());
         assert_eq!(lr.def(), i11.into());
         assert_eq!(lr.def_local_end(), i13.into());
@@ -611,17 +600,17 @@ mod tests {
 
     #[test]
     fn local_arg() {
         let v0 = Value::new(0);
         let e10 = Ebb::new(10);
         let i11 = Inst::new(11);
         let i12 = Inst::new(12);
         let i13 = Inst::new(13);
-        let mut lr = GenLiveRange::new(v0, e10.into(), Default::default());
+        let mut lr = GenericLiveRange::new(v0, e10.into(), Default::default());
         let forest = &mut bforest::MapForest::new();
 
         // Extending a dead EBB argument in its own block should not indicate that a live-in
         // interval was created.
         assert_eq!(lr.extend_in_ebb(e10, i12, PO, forest), false);
         PO.validate(&lr, forest);
         assert!(!lr.is_dead());
         assert!(lr.is_local());
@@ -646,100 +635,68 @@ mod tests {
         let v0 = Value::new(0);
         let e10 = Ebb::new(10);
         let i11 = Inst::new(11);
         let i12 = Inst::new(12);
         let e20 = Ebb::new(20);
         let i21 = Inst::new(21);
         let i22 = Inst::new(22);
         let i23 = Inst::new(23);
-        let mut lr = GenLiveRange::new(v0, i11.into(), Default::default());
+        let mut lr = GenericLiveRange::new(v0, i11.into(), Default::default());
         let forest = &mut bforest::MapForest::new();
 
         assert_eq!(lr.extend_in_ebb(e10, i12, PO, forest), false);
 
         // Adding a live-in interval.
         assert_eq!(lr.extend_in_ebb(e20, i22, PO, forest), true);
         PO.validate(&lr, forest);
-        assert_eq!(
-            lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)),
-            Some(i22)
-        );
+        assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i22));
 
         // Non-extending the live-in.
         assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), false);
-        assert_eq!(
-            lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)),
-            Some(i22)
-        );
+        assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i22));
 
         // Extending the existing live-in.
         assert_eq!(lr.extend_in_ebb(e20, i23, PO, forest), false);
         PO.validate(&lr, forest);
-        assert_eq!(
-            lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)),
-            Some(i23)
-        );
+        assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i23));
     }
 
     #[test]
     fn coalesce() {
         let v0 = Value::new(0);
         let i11 = Inst::new(11);
         let e20 = Ebb::new(20);
         let i21 = Inst::new(21);
         let e30 = Ebb::new(30);
         let i31 = Inst::new(31);
         let e40 = Ebb::new(40);
         let i41 = Inst::new(41);
-        let mut lr = GenLiveRange::new(v0, i11.into(), Default::default());
+        let mut lr = GenericLiveRange::new(v0, i11.into(), Default::default());
         let forest = &mut bforest::MapForest::new();
 
         assert_eq!(lr.extend_in_ebb(e30, i31, PO, forest), true);
-        assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
-            [(e30, i31)]
-        );
+        assert_eq!(lr.liveins(forest).collect::<Vec<_>>(), [(e30, i31)]);
 
         // Coalesce to previous
         assert_eq!(lr.extend_in_ebb(e40, i41, PO, forest), true);
-        assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
-            [(e30, i41)]
-        );
+        assert_eq!(lr.liveins(forest).collect::<Vec<_>>(), [(e30, i41)]);
 
         // Coalesce to next
         assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), true);
-        assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
-            [(e20, i41)]
-        );
+        assert_eq!(lr.liveins(forest).collect::<Vec<_>>(), [(e20, i41)]);
 
-        let mut lr = GenLiveRange::new(v0, i11.into(), Default::default());
+        let mut lr = GenericLiveRange::new(v0, i11.into(), Default::default());
 
         assert_eq!(lr.extend_in_ebb(e40, i41, PO, forest), true);
-        assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
-            [(e40, i41)]
-        );
+        assert_eq!(lr.liveins(forest).collect::<Vec<_>>(), [(e40, i41)]);
 
         assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), true);
         assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
+            lr.liveins(forest).collect::<Vec<_>>(),
             [(e20, i21), (e40, i41)]
         );
 
         // Coalesce to previous and next
         assert_eq!(lr.extend_in_ebb(e30, i31, PO, forest), true);
-        assert_eq!(
-            lr.liveins(LiveRangeContext::new(PO, forest))
-                .collect::<Vec<_>>(),
-            [(e20, i41)]
-        );
+        assert_eq!(lr.liveins(forest).collect::<Vec<_>>(), [(e20, i41)]);
     }
-
-    // TODO: Add more tests that exercise the binary search algorithm.
 }
--- a/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
@@ -314,27 +314,28 @@ impl<'a> Context<'a> {
     // class operand, they two are compatible. We are also assuming that two register class
     // operands are always compatible.
     fn collect_reg_uses(&mut self, inst: Inst, ebb: Ebb, constraints: Option<&RecipeConstraints>) {
         let args = self.cur.func.dfg.inst_args(inst);
         let num_fixed_ins = if let Some(constraints) = constraints {
             for (idx, (op, &arg)) in constraints.ins.iter().zip(args).enumerate() {
                 let mut reguse = RegUse::new(arg, idx, op.regclass.into());
                 let lr = &self.liveness[arg];
-                let ctx = self.liveness.context(&self.cur.func.layout);
                 match op.kind {
                     ConstraintKind::Stack => continue,
                     ConstraintKind::FixedReg(_) => reguse.fixed = true,
                     ConstraintKind::Tied(_) => {
                         // A tied operand must kill the used value.
-                        reguse.tied = !lr.killed_at(inst, ebb, ctx);
+                        reguse.tied =
+                            !lr.killed_at(inst, ebb, self.liveness.forest(), &self.cur.func.layout);
                     }
                     ConstraintKind::FixedTied(_) => {
                         reguse.fixed = true;
-                        reguse.tied = !lr.killed_at(inst, ebb, ctx);
+                        reguse.tied =
+                            !lr.killed_at(inst, ebb, self.liveness.forest(), &self.cur.func.layout);
                     }
                     ConstraintKind::Reg => {}
                 }
                 if lr.affinity.is_stack() {
                     reguse.spilled = true;
                 }
 
                 // Only collect the interesting register uses.
--- a/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/virtregs.rs
@@ -13,19 +13,19 @@
 
 use crate::dbg::DisplayList;
 use crate::dominator_tree::DominatorTreePreorder;
 use crate::entity::entity_impl;
 use crate::entity::{EntityList, ListPool};
 use crate::entity::{Keys, PrimaryMap, SecondaryMap};
 use crate::ir::{Function, Value};
 use crate::packed_option::PackedOption;
-use crate::ref_slice::ref_slice;
 use core::cmp::Ordering;
 use core::fmt;
+use core::slice;
 use smallvec::SmallVec;
 use std::vec::Vec;
 
 /// A virtual register reference.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct VirtReg(u32);
 entity_impl!(VirtReg, "vreg");
 
@@ -99,17 +99,17 @@ impl VirtRegs {
     /// If `value` belongs to a virtual register, the congruence class is the values of the virtual
     /// register. Otherwise it is just the value itself.
     #[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
     pub fn congruence_class<'a, 'b>(&'a self, value: &'b Value) -> &'b [Value]
     where
         'a: 'b,
     {
         self.get(*value)
-            .map_or_else(|| ref_slice(value), |vr| self.values(vr))
+            .map_or_else(|| slice::from_ref(value), |vr| self.values(vr))
     }
 
     /// Check if `a` and `b` belong to the same congruence class.
     pub fn same_class(&self, a: Value, b: Value) -> bool {
         match (self.get(a), self.get(b)) {
             (Some(va), Some(vb)) => va == vb,
             _ => a == b,
         }
--- a/third_party/rust/cranelift-codegen/src/settings.rs
+++ b/third_party/rust/cranelift-codegen/src/settings.rs
@@ -9,20 +9,20 @@
 //! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
 //! create it.
 //!
 //! # Example
 //! ```
 //! use cranelift_codegen::settings::{self, Configurable};
 //!
 //! let mut b = settings::builder();
-//! b.set("opt_level", "fastest");
+//! b.set("opt_level", "speed_and_size");
 //!
 //! let f = settings::Flags::new(b);
-//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
+//! assert_eq!(f.opt_level(), settings::OptLevel::SpeedAndSize);
 //! ```
 
 use crate::constant_hash::{probe, simple_hash};
 use crate::isa::TargetIsa;
 use core::fmt;
 use core::str;
 use failure_derive::Fail;
 use std::boxed::Box;
@@ -373,17 +373,17 @@ mod tests {
 
     #[test]
     fn display_default() {
         let b = builder();
         let f = Flags::new(b);
         assert_eq!(
             f.to_string(),
             "[shared]\n\
-             opt_level = \"default\"\n\
+             opt_level = \"none\"\n\
              libcall_call_conv = \"isa_default\"\n\
              baldrdash_prologue_words = 0\n\
              probestack_size_log2 = 12\n\
              enable_verifier = true\n\
              is_pic = false\n\
              colocated_libcalls = false\n\
              avoid_div_traps = false\n\
              enable_float = true\n\
@@ -393,17 +393,17 @@ mod tests {
              enable_simd = false\n\
              enable_atomics = true\n\
              enable_safepoints = false\n\
              allones_funcaddrs = false\n\
              probestack_enabled = true\n\
              probestack_func_adjusts_sp = false\n\
              jump_tables_enabled = true\n"
         );
-        assert_eq!(f.opt_level(), super::OptLevel::Default);
+        assert_eq!(f.opt_level(), super::OptLevel::None);
         assert_eq!(f.enable_simd(), false);
         assert_eq!(f.baldrdash_prologue_words(), 0);
     }
 
     #[test]
     fn modify_bool() {
         let mut b = builder();
         assert_eq!(b.enable("not_there"), Err(BadName("not_there".to_string())));
@@ -423,18 +423,20 @@ mod tests {
         );
         assert_eq!(b.set("enable_simd", ""), Err(BadValue("bool".to_string())));
         assert_eq!(
             b.set("enable_simd", "best"),
             Err(BadValue("bool".to_string()))
         );
         assert_eq!(
             b.set("opt_level", "true"),
-            Err(BadValue("any among default, best, fastest".to_string()))
+            Err(BadValue(
+                "any among none, speed, speed_and_size".to_string()
+            ))
         );
-        assert_eq!(b.set("opt_level", "best"), Ok(()));
+        assert_eq!(b.set("opt_level", "speed"), Ok(()));
         assert_eq!(b.set("enable_simd", "0"), Ok(()));
 
         let f = Flags::new(b);
         assert_eq!(f.enable_simd(), false);
-        assert_eq!(f.opt_level(), super::OptLevel::Best);
+        assert_eq!(f.opt_level(), super::OptLevel::Speed);
     }
 }
--- a/third_party/rust/cranelift-codegen/src/topo_order.rs
+++ b/third_party/rust/cranelift-codegen/src/topo_order.rs
@@ -1,12 +1,12 @@
 //! Topological order of EBBs, according to the dominator tree.
 
 use crate::dominator_tree::DominatorTree;
-use crate::entity::SparseSet;
+use crate::entity::EntitySet;
 use crate::ir::{Ebb, Layout};
 use std::vec::Vec;
 
 /// Present EBBs in a topological order such that all dominating EBBs are guaranteed to be visited
 /// before the current EBB.
 ///
 /// There are many topological orders of the EBBs in a function, so it is possible to provide a
 /// preferred order, and the `TopoOrder` will present EBBs in an order that is as close as possible
@@ -14,29 +14,29 @@ use std::vec::Vec;
 pub struct TopoOrder {
     /// Preferred order of EBBs to visit.
     preferred: Vec<Ebb>,
 
     /// Next entry to get from `preferred`.
     next: usize,
 
     /// Set of visited EBBs.
-    visited: SparseSet<Ebb>,
+    visited: EntitySet<Ebb>,
 
     /// Stack of EBBs to be visited next, already in `visited`.
     stack: Vec<Ebb>,
 }
 
 impl TopoOrder {
     /// Create a new empty topological order.
     pub fn new() -> Self {
         Self {
             preferred: Vec::new(),
             next: 0,
-            visited: SparseSet::new(),
+            visited: EntitySet::new(),
             stack: Vec::new(),
         }
     }
 
     /// Clear all data structures in this topological order.
     pub fn clear(&mut self) {
         self.preferred.clear();
         self.next = 0;
@@ -59,26 +59,27 @@ impl TopoOrder {
 
     /// Get the next EBB in the topological order.
     ///
     /// Two things are guaranteed about the EBBs returned by this function:
     ///
     /// - All EBBs in the `preferred` iterator given to `reset` will be returned.
     /// - All dominators are visited before the EBB returned.
     pub fn next(&mut self, layout: &Layout, domtree: &DominatorTree) -> Option<Ebb> {
+        self.visited.resize(layout.ebb_capacity());
         // Any entries in `stack` should be returned immediately. They have already been added to
         // `visited`.
         while self.stack.is_empty() {
             match self.preferred.get(self.next).cloned() {
                 None => return None,
                 Some(mut ebb) => {
                     // We have the next EBB in the preferred order.
                     self.next += 1;
                     // Push it along with any non-visited dominators.
-                    while self.visited.insert(ebb).is_none() {
+                    while self.visited.insert(ebb) {
                         self.stack.push(ebb);
                         match domtree.idom(ebb) {
                             Some(idom) => ebb = layout.inst_ebb(idom).expect("idom not in layout"),
                             None => break,
                         }
                     }
                 }
             }
--- a/third_party/rust/cranelift-codegen/src/value_label.rs
+++ b/third_party/rust/cranelift-codegen/src/value_label.rs
@@ -91,18 +91,18 @@ where
     T: From<SourceLoc> + Deref<Target = SourceLoc> + Ord + Copy,
 {
     let values_labels = build_value_labels_index::<T>(func);
 
     let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
     ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase
     let encinfo = isa.encoding_info();
     let values_locations = &func.locations;
-    let liveness_context = regalloc.liveness().context(&func.layout);
     let liveness_ranges = regalloc.liveness().ranges();
+    let liveness_forest = regalloc.liveness().forest();
 
     let mut ranges = HashMap::new();
     let mut add_range = |label, range: (u32, u32), loc: ValueLoc| {
         if range.0 >= range.1 || !loc.is_assigned() {
             return;
         }
         if !ranges.contains_key(&label) {
             ranges.insert(label, Vec::new());
@@ -121,17 +121,20 @@ where
         divert.at_ebb(&func.entry_diversions, ebb);
         let mut last_srcloc: Option<T> = None;
         for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
             divert.apply(&func.dfg[inst]);
             end_offset = offset + size;
             // Remove killed values.
             tracked_values.retain(|(x, label, start_offset, last_loc)| {
                 let range = liveness_ranges.get(*x);
-                if range.expect("value").killed_at(inst, ebb, liveness_context) {
+                if range
+                    .expect("value")
+                    .killed_at(inst, ebb, &liveness_forest, &func.layout)
+                {
                     add_range(*label, (*start_offset, end_offset), *last_loc);
                     return false;
                 }
                 return true;
             });
 
             let srcloc = func.srclocs[inst];
             if srcloc.is_default() {
@@ -168,17 +171,17 @@ where
                 },
                 Included(srcloc),
             );
             let active_values = values_labels.range(range);
             let active_values = active_values.filter(|(_, (v, _))| {
                 // Ignore dead/inactive Values.
                 let range = liveness_ranges.get(*v);
                 match range {
-                    Some(r) => r.reaches_use(inst, ebb, liveness_context),
+                    Some(r) => r.reaches_use(inst, ebb, &liveness_forest, &func.layout),
                     None => false,
                 }
             });
             // Append new Values to the tracked_values.
             for (_, (val, label)) in active_values {
                 let loc = divert.get(*val, values_locations);
                 tracked_values.push((*val, *label, end_offset, loc));
             }
--- a/third_party/rust/cranelift-codegen/src/verifier/cssa.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/cssa.rs
@@ -113,18 +113,22 @@ impl<'a> CssaVerifier<'a> {
                 // We only have to check against the nearest dominating value.
                 for &prev_val in values[0..idx].iter().rev() {
                     let prev_def: ExpandedProgramPoint = self.func.dfg.value_def(prev_val).into();
                     let prev_ebb = self.func.layout.pp_ebb(prev_def);
 
                     if self.preorder.dominates(prev_ebb, def_ebb)
                         && self.domtree.dominates(prev_def, def, &self.func.layout)
                     {
-                        let ctx = self.liveness.context(&self.func.layout);
-                        if self.liveness[prev_val].overlaps_def(def, def_ebb, ctx) {
+                        if self.liveness[prev_val].overlaps_def(
+                            def,
+                            def_ebb,
+                            self.liveness.forest(),
+                            &self.func.layout,
+                        ) {
                             return fatal!(
                                 errors,
                                 val,
                                 "Value def in {} = {} interferes with {}",
                                 vreg,
                                 DisplayList(values),
                                 prev_val
                             );
--- a/third_party/rust/cranelift-codegen/src/verifier/flags.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/flags.rs
@@ -1,11 +1,11 @@
 //! Verify CPU flags values.
 
-use crate::entity::{SecondaryMap, SparseSet};
+use crate::entity::{EntitySet, SecondaryMap};
 use crate::flowgraph::{BasicBlock, ControlFlowGraph};
 use crate::ir;
 use crate::ir::instructions::BranchInfo;
 use crate::isa;
 use crate::packed_option::PackedOption;
 use crate::timing;
 use crate::verifier::{VerifierErrors, VerifierStepResult};
 
@@ -45,17 +45,17 @@ struct FlagsVerifier<'a> {
     /// The single live-in flags value (if any) for each EBB.
     livein: SecondaryMap<ir::Ebb, PackedOption<ir::Value>>,
 }
 
 impl<'a> FlagsVerifier<'a> {
     fn check(&mut self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
         // List of EBBs that need to be processed. EBBs may be re-added to this list when we detect
         // that one of their successor blocks needs a live-in flags value.
-        let mut worklist = SparseSet::new();
+        let mut worklist = EntitySet::with_capacity(self.func.layout.ebb_capacity());
         for ebb in self.func.layout.ebbs() {
             worklist.insert(ebb);
         }
 
         while let Some(ebb) = worklist.pop() {
             if let Some(value) = self.visit_ebb(ebb, errors)? {
                 // The EBB has live-in flags. Check if the value changed.
                 match self.livein[ebb].expand() {
--- a/third_party/rust/cranelift-codegen/src/verifier/liveness.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/liveness.rs
@@ -1,19 +1,18 @@
 //! Liveness verifier.
 
 use crate::flowgraph::{BasicBlock, ControlFlowGraph};
 use crate::ir::entities::AnyEntity;
-use crate::ir::{ExpandedProgramPoint, Function, Inst, ProgramOrder, ProgramPoint, Value};
+use crate::ir::{ExpandedProgramPoint, Function, ProgramPoint, Value};
 use crate::isa::TargetIsa;
 use crate::regalloc::liveness::Liveness;
 use crate::regalloc::liverange::LiveRange;
 use crate::timing;
 use crate::verifier::{VerifierErrors, VerifierStepResult};
-use core::cmp::Ordering;
 
 /// Verify liveness information for `func`.
 ///
 /// The provided control flow graph is assumed to be sound.
 ///
 /// - All values in the program must have a live range.
 /// - The live range def point must match where the value is defined.
 /// - The live range must reach all uses.
@@ -101,17 +100,19 @@ impl<'a> LivenessVerifier<'a> {
                 }
 
                 // Check the uses.
                 for &val in self.func.dfg.inst_args(inst) {
                     let lr = match self.liveness.get(val) {
                         Some(lr) => lr,
                         None => return fatal!(errors, inst, "{} has no live range", val),
                     };
-                    if !self.live_at_use(lr, inst) {
+
+                    debug_assert!(self.func.layout.inst_ebb(inst).unwrap() == ebb);
+                    if !lr.reaches_use(inst, ebb, self.liveness.forest(), &self.func.layout) {
                         return fatal!(errors, inst, "{} is not live at this use", val);
                     }
 
                     // A legal instruction is not allowed to depend on ghost values.
                     if encoding.is_legal() && lr.affinity.is_unassigned() {
                         return fatal!(
                             errors,
                             inst,
@@ -121,34 +122,16 @@ impl<'a> LivenessVerifier<'a> {
                         );
                     }
                 }
             }
         }
         Ok(())
     }
 
-    /// Is `lr` live at the use `inst`?
-    fn live_at_use(&self, lr: &LiveRange, inst: Inst) -> bool {
-        let ctx = self.liveness.context(&self.func.layout);
-
-        // Check if `inst` is in the def range, not including the def itself.
-        if ctx.order.cmp(lr.def(), inst) == Ordering::Less
-            && ctx.order.cmp(inst, lr.def_local_end()) != Ordering::Greater
-        {
-            return true;
-        }
-
-        // Otherwise see if `inst` is in one of the live-in ranges.
-        match lr.livein_local_end(ctx.order.inst_ebb(inst).unwrap(), ctx) {
-            Some(end) => ctx.order.cmp(inst, end) != Ordering::Greater,
-            None => false,
-        }
-    }
-
     /// Check the integrity of the live range `lr`.
     fn check_lr(
         &self,
         def: ProgramPoint,
         val: Value,
         lr: &LiveRange,
         errors: &mut VerifierErrors,
     ) -> VerifierStepResult<()> {
@@ -191,17 +174,17 @@ impl<'a> LivenessVerifier<'a> {
             ExpandedProgramPoint::Inst(i) => {
                 if self.func.layout.inst_ebb(i) != Some(def_ebb) {
                     return fatal!(errors, loc, "Def local end for {} in wrong ebb", val);
                 }
             }
         }
 
         // Now check the live-in intervals against the CFG.
-        for (mut ebb, end) in lr.liveins(self.liveness.context(l)) {
+        for (mut ebb, end) in lr.liveins(self.liveness.forest()) {
             if !l.is_ebb_inserted(ebb) {
                 return fatal!(
                     errors,
                     loc,
                     "{} livein at {} which is not in the layout",
                     val,
                     ebb
                 );
@@ -218,18 +201,18 @@ impl<'a> LivenessVerifier<'a> {
                         end
                     );
                 }
             };
 
             // Check all the EBBs in the interval independently.
             loop {
                 // If `val` is live-in at `ebb`, it must be live at all the predecessors.
-                for BasicBlock { inst: pred, .. } in self.cfg.pred_iter(ebb) {
-                    if !self.live_at_use(lr, pred) {
+                for BasicBlock { inst: pred, ebb } in self.cfg.pred_iter(ebb) {
+                    if !lr.reaches_use(pred, ebb, self.liveness.forest(), &self.func.layout) {
                         return fatal!(
                             errors,
                             pred,
                             "{} is live in to {} but not live at predecessor",
                             val,
                             ebb
                         );
                     }
--- a/third_party/rust/cranelift-codegen/src/verifier/locations.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/locations.rs
@@ -329,20 +329,20 @@ impl<'a> LocationVerifier<'a> {
             ),
             SingleDest(ebb, _) => {
                 let unique_predecessor = self.cfg.pred_iter(ebb).count() == 1;
                 let mut val_to_remove = vec![];
                 for (&value, d) in divert.iter() {
                     let lr = &liveness[value];
                     if is_after_branch && unique_predecessor {
                         // Forward diversions based on the targeted branch.
-                        if !lr.is_livein(ebb, liveness.context(&self.func.layout)) {
+                        if !lr.is_livein(ebb, liveness.forest(), &self.func.layout) {
                             val_to_remove.push(value)
                         }
-                    } else if lr.is_livein(ebb, liveness.context(&self.func.layout)) {
+                    } else if lr.is_livein(ebb, liveness.forest(), &self.func.layout) {
                         return fatal!(
                             errors,
                             inst,
                             "SingleDest: {} is diverted to {} and live in to {}",
                             value,
                             d.to.display(&self.reginfo),
                             ebb
                         );
@@ -354,29 +354,29 @@ impl<'a> LocationVerifier<'a> {
                     }
                     debug_assert!(divert.check_ebb_entry(&self.func.entry_diversions, ebb));
                 }
             }
             Table(jt, ebb) => {
                 for (&value, d) in divert.iter() {
                     let lr = &liveness[value];
                     if let Some(ebb) = ebb {
-                        if lr.is_livein(ebb, liveness.context(&self.func.layout)) {
+                        if lr.is_livein(ebb, liveness.forest(), &self.func.layout) {
                             return fatal!(
                                 errors,
                                 inst,
                                 "Table.default: {} is diverted to {} and live in to {}",
                                 value,
                                 d.to.display(&self.reginfo),
                                 ebb
                             );
                         }
                     }
                     for ebb in self.func.jump_tables[jt].iter() {
-                        if lr.is_livein(*ebb, liveness.context(&self.func.layout)) {
+                        if lr.is_livein(*ebb, liveness.forest(), &self.func.layout) {
                             return fatal!(
                                 errors,
                                 inst,
                                 "Table.case: {} is diverted to {} and live in to {}",
                                 value,
                                 d.to.display(&self.reginfo),
                                 ebb
                             );
--- a/third_party/rust/cranelift-codegen/src/verifier/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/mod.rs
@@ -691,28 +691,36 @@ impl<'a> Verifier<'a> {
                             "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg"
                         );
                     }
                 } else {
                     return fatal!(errors, inst, "GetPinnedReg/SetPinnedReg need an ISA!");
                 }
             }
 
+            Unary {
+                opcode: Opcode::Bitcast,
+                arg,
+            } => {
+                self.verify_bitcast(inst, arg, errors)?;
+            }
+
             // Exhaustive list so we can't forget to add new formats
             Unary { .. }
             | UnaryImm { .. }
-            | UnaryImm128 { .. }
             | UnaryIeee32 { .. }
             | UnaryIeee64 { .. }
             | UnaryBool { .. }
             | Binary { .. }
             | BinaryImm { .. }
             | Ternary { .. }
             | InsertLane { .. }
             | ExtractLane { .. }
+            | UnaryConst { .. }
+            | Shuffle { .. }
             | IntCompare { .. }
             | IntCompareImm { .. }
             | IntCond { .. }
             | FloatCompare { .. }
             | FloatCond { .. }
             | IntSelect { .. }
             | Load { .. }
             | Store { .. }
@@ -976,16 +984,38 @@ impl<'a> Verifier<'a> {
                 errors,
                 loc_inst,
                 "instruction result {} is not defined by the instruction",
                 v
             ),
         }
     }
 
+    fn verify_bitcast(
+        &self,
+        inst: Inst,
+        arg: Value,
+        errors: &mut VerifierErrors,
+    ) -> VerifierStepResult<()> {
+        let typ = self.func.dfg.ctrl_typevar(inst);
+        let value_type = self.func.dfg.value_type(arg);
+
+        if typ.lane_bits() < value_type.lane_bits() {
+            fatal!(
+                errors,
+                inst,
+                "The bitcast argument {} doesn't fit in a type of {} bits",
+                arg,
+                typ.lane_bits()
+            )
+        } else {
+            Ok(())
+        }
+    }
+
     fn domtree_integrity(
         &self,
         domtree: &DominatorTree,
         errors: &mut VerifierErrors,
     ) -> VerifierStepResult<()> {
         // We consider two `DominatorTree`s to be equal if they return the same immediate
         // dominator for each EBB. Therefore the current domtree is valid if it matches the freshly
         // computed one.
@@ -1741,31 +1771,57 @@ impl<'a> Verifier<'a> {
 
     fn immediate_constraints(
         &self,
         inst: Inst,
         errors: &mut VerifierErrors,
     ) -> VerifierStepResult<()> {
         let inst_data = &self.func.dfg[inst];
 
-        // If this is some sort of a store instruction, get the memflags, else, just return.
-        let memflags = match *inst_data {
+        match *inst_data {
             ir::InstructionData::Store { flags, .. }
-            | ir::InstructionData::StoreComplex { flags, .. } => flags,
-            _ => return Ok(()),
-        };
-
-        if memflags.readonly() {
-            fatal!(
-                errors,
-                inst,
-                "A store instruction cannot have the `readonly` MemFlag"
-            )
-        } else {
-            Ok(())
+            | ir::InstructionData::StoreComplex { flags, .. } => {
+                if flags.readonly() {
+                    fatal!(
+                        errors,
+                        inst,
+                        "A store instruction cannot have the `readonly` MemFlag"
+                    )
+                } else {
+                    Ok(())
+                }
+            }
+            ir::InstructionData::ExtractLane {
+                opcode: ir::instructions::Opcode::Extractlane,
+                lane,
+                arg,
+                ..
+            }
+            | ir::InstructionData::InsertLane {
+                opcode: ir::instructions::Opcode::Insertlane,
+                lane,
+                args: [arg, _],
+                ..
+            } => {
+                // We must be specific about the opcodes above because other instructions are using
+                // the ExtractLane/InsertLane formats.
+                let ty = self.func.dfg.value_type(arg);
+                if u16::from(lane) >= ty.lane_count() {
+                    fatal!(
+                        errors,
+                        inst,
+                        "The lane {} does not index into the type {}",
+                        lane,
+                        ty
+                    )
+                } else {
+                    Ok(())
+                }
+            }
+            _ => Ok(()),
         }
     }
 
     fn verify_safepoint_unused(
         &self,
         inst: Inst,
         errors: &mut VerifierErrors,
     ) -> VerifierStepResult<()> {
@@ -1777,22 +1833,61 @@ impl<'a> Verifier<'a> {
                     inst,
                     "safepoint instruction cannot be used when it is not enabled."
                 );
             }
         }
         Ok(())
     }
 
+    fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
+        self.func
+            .signature
+            .params
+            .iter()
+            .enumerate()
+            .filter(|(_, &param)| param.value_type == types::INVALID)
+            .for_each(|(i, _)| {
+                report!(
+                    errors,
+                    AnyEntity::Function,
+                    "Parameter at position {} has an invalid type",
+                    i
+                );
+            });
+
+        self.func
+            .signature
+            .returns
+            .iter()
+            .enumerate()
+            .filter(|(_, &ret)| ret.value_type == types::INVALID)
+            .for_each(|(i, _)| {
+                report!(
+                    errors,
+                    AnyEntity::Function,
+                    "Return value at position {} has an invalid type",
+                    i
+                )
+            });
+
+        if errors.has_error() {
+            Err(())
+        } else {
+            Ok(())
+        }
+    }
+
     pub fn run(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
         self.verify_global_values(errors)?;
         self.verify_heaps(errors)?;
         self.verify_tables(errors)?;
         self.verify_jump_tables(errors)?;
         self.typecheck_entry_block_params(errors)?;
+        self.typecheck_function_signature(errors)?;
 
         for ebb in self.func.layout.ebbs() {
             for inst in self.func.layout.ebb_insts(ebb) {
                 self.ebb_integrity(ebb, inst, errors)?;
                 self.instruction_integrity(inst, errors)?;
                 self.verify_safepoint_unused(inst, errors)?;
                 self.typecheck(inst, errors)?;
                 self.verify_encoding(inst, errors)?;
@@ -1809,17 +1904,17 @@ impl<'a> Verifier<'a> {
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::{Verifier, VerifierError, VerifierErrors};
     use crate::entity::EntityList;
     use crate::ir::instructions::{InstructionData, Opcode};
-    use crate::ir::Function;
+    use crate::ir::{types, AbiParam, Function};
     use crate::settings;
 
     macro_rules! assert_err_with_msg {
         ($e:expr, $msg:expr) => {
             match $e.0.get(0) {
                 None => panic!("Expected an error"),
                 Some(&VerifierError { ref message, .. }) => {
                     if !message.contains($msg) {
@@ -1868,9 +1963,35 @@ mod tests {
         let flags = &settings::Flags::new(settings::builder());
         let verifier = Verifier::new(&func, flags.into());
         let mut errors = VerifierErrors::default();
 
         let _ = verifier.run(&mut errors);
 
         assert_err_with_msg!(errors, "instruction format");
     }
+
+    #[test]
+    fn test_function_invalid_param() {
+        let mut func = Function::new();
+        func.signature.params.push(AbiParam::new(types::INVALID));
+
+        let mut errors = VerifierErrors::default();
+        let flags = &settings::Flags::new(settings::builder());
+        let verifier = Verifier::new(&func, flags.into());
+
+        let _ = verifier.typecheck_function_signature(&mut errors);
+        assert_err_with_msg!(errors, "Parameter at position 0 has an invalid type");
+    }
+
+    #[test]
+    fn test_function_invalid_return_value() {
+        let mut func = Function::new();
+        func.signature.returns.push(AbiParam::new(types::INVALID));
+
+        let mut errors = VerifierErrors::default();
+        let flags = &settings::Flags::new(settings::builder());
+        let verifier = Verifier::new(&func, flags.into());
+
+        let _ = verifier.typecheck_function_signature(&mut errors);
+        assert_err_with_msg!(errors, "Return value at position 0 has an invalid type");
+    }
 }
--- a/third_party/rust/cranelift-codegen/src/write.rs
+++ b/third_party/rust/cranelift-codegen/src/write.rs
@@ -1,16 +1,16 @@
 //! Converting Cranelift IR to text.
 //!
 //! The `write` module provides the `write_function` function which converts an IR `Function` to an
 //! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate.
 
 use crate::entity::SecondaryMap;
 use crate::ir::entities::AnyEntity;
-use crate::ir::immediates::Uimm128;
+use crate::ir::immediates::V128Imm;
 use crate::ir::{
     DataFlowGraph, DisplayFunctionAnnotations, Ebb, Function, Inst, SigRef, Type, Value, ValueDef,
     ValueLoc,
 };
 use crate::isa::{RegInfo, TargetIsa};
 use crate::packed_option::ReservedValue;
 use crate::value_label::ValueLabelsRanges;
 use core::fmt::{self, Write};
@@ -483,21 +483,16 @@ pub fn write_operands(
     isa: Option<&dyn TargetIsa>,
     inst: Inst,
 ) -> fmt::Result {
     let pool = &dfg.value_lists;
     use crate::ir::instructions::InstructionData::*;
     match dfg[inst] {
         Unary { arg, .. } => write!(w, " {}", arg),
         UnaryImm { imm, .. } => write!(w, " {}", imm),
-        UnaryImm128 { imm, .. } => {
-            let data = dfg.constants.get(imm);
-            let uimm128 = Uimm128::from(&data[..]);
-            write!(w, " {}", uimm128)
-        }
         UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
         UnaryIeee64 { imm, .. } => write!(w, " {}", imm),
         UnaryBool { imm, .. } => write!(w, " {}", imm),
         UnaryGlobalValue { global_value, .. } => write!(w, " {}", global_value),
         Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
         BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
         Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
         MultiAry { ref args, .. } => {
@@ -505,16 +500,30 @@ pub fn write_operands(
                 write!(w, "")
             } else {
                 write!(w, " {}", DisplayValues(args.as_slice(pool)))
             }
         }
         NullAry { .. } => write!(w, " "),
         InsertLane { lane, args, .. } => write!(w, " {}, {}, {}", args[0], lane, args[1]),
         ExtractLane { lane, arg, .. } => write!(w, " {}, {}", arg, lane),
+        UnaryConst {
+            constant_handle, ..
+        } => {
+            let data = dfg.constants.get(constant_handle);
+            let v128 = V128Imm::from(&data[..]);
+            write!(w, " {}", v128)
+        }
+        Shuffle { mask, args, .. } => {
+            let data = dfg.immediates.get(mask).expect(
+                "Expected the shuffle mask to already be inserted into the immediates table",
+            );
+            let v128 = V128Imm::from(&data[..]);
+            write!(w, " {}, {}, {}", args[0], args[1], v128)
+        }
         IntCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
         IntCompareImm { cond, arg, imm, .. } => write!(w, " {} {}, {}", cond, arg, imm),
         IntCond { cond, arg, .. } => write!(w, " {} {}", cond, arg),
         FloatCompare { cond, args, .. } => write!(w, " {} {}, {}", cond, args[0], args[1]),
         FloatCond { cond, arg, .. } => write!(w, " {} {}", cond, arg),
         IntSelect { cond, args, .. } => {
             write!(w, " {} {}, {}, {}", cond, args[0], args[1], args[2])
         }
--- a/third_party/rust/cranelift-entity/.cargo-checksum.json
+++ b/third_party/rust/cranelift-entity/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6625897aa38b637e103d905200be02306f4efd8fb06681d69ecf005468a965cb","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"c47e858b6a46f8b5f584ca7f83c466e0fa616bbed9cb28622c53d4c1faf197c4","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"7aa57f77ae010ceabbff08700eca020030ec8ca16342db1f7e7390d186b3c156","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"8237b5c473fd219dc606efd7c989ec5216e4ae62c6cbb2857fbe11593c42aae9","src/set.rs":"97b860818c9577546201271f7ca457a5784c2e4447b68202a274f7fe75e937f2","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"a355d658ab113a09938162676fde122551e54bd86be0699e3e763a0074b3c73f","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"c47e858b6a46f8b5f584ca7f83c466e0fa616bbed9cb28622c53d4c1faf197c4","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"7aa57f77ae010ceabbff08700eca020030ec8ca16342db1f7e7390d186b3c156","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"8237b5c473fd219dc606efd7c989ec5216e4ae62c6cbb2857fbe11593c42aae9","src/set.rs":"eeb3b67030083aa6dd35c0ea7c50130d1cf6693ce302f902928440d5807d5472","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-entity/Cargo.toml
+++ b/third_party/rust/cranelift-entity/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-entity"
-version = "0.42.0"
+version = "0.44.0"
 description = "Data structures using entity references as mapping keys"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://cranelift.readthedocs.io/"
 repository = "https://github.com/CraneStation/cranelift"
 categories = ["no-std"]
 readme = "README.md"
 keywords = ["entity", "set", "map"]
 edition = "2018"
--- a/third_party/rust/cranelift-entity/src/set.rs
+++ b/third_party/rust/cranelift-entity/src/set.rs
@@ -28,31 +28,41 @@ where
     pub fn new() -> Self {
         Self {
             elems: Vec::new(),
             len: 0,
             unused: PhantomData,
         }
     }
 
+    /// Creates a new empty set with the specified capacity.
+    pub fn with_capacity(capacity: usize) -> Self {
+        Self {
+            elems: Vec::with_capacity((capacity + 7) / 8),
+            ..Self::new()
+        }
+    }
+
     /// Get the element at `k` if it exists.
     pub fn contains(&self, k: K) -> bool {
         let index = k.index();
         if index < self.len {
             (self.elems[index / 8] & (1 << (index % 8))) != 0
         } else {
             false
         }
     }
 
     /// Is this set completely empty?
     pub fn is_empty(&self) -> bool {
-        // Note that this implementation will become incorrect should it ever become possible
-        // to remove elements from an `EntitySet`.
-        self.len == 0
+        if self.len != 0 {
+            false
+        } else {
+            self.elems.iter().all(|&e| e == 0)
+        }
     }
 
     /// Returns the cardinality of the set.  More precisely, it returns the number of calls to
     /// `insert` with different key values, that have happened since the the set was most recently
     /// `clear`ed or created with `new`.
     pub fn cardinality(&self) -> usize {
         let mut n: usize = 0;
         for byte_ix in 0..self.len / 8 {
@@ -88,25 +98,53 @@ where
         let index = k.index();
         if index >= self.len {
             self.resize(index + 1)
         }
         let result = !self.contains(k);
         self.elems[index / 8] |= 1 << (index % 8);
         result
     }
+
+    /// Removes and returns the entity from the set if it exists.
+    pub fn pop(&mut self) -> Option<K> {
+        if self.len == 0 {
+            return None;
+        }
+
+        // Clear the last known entity in the list.
+        let last_index = self.len - 1;
+        self.elems[last_index / 8] &= !(1 << (last_index % 8));
+
+        // Set the length to the next last stored entity or zero if we pop'ed
+        // the last entity.
+        self.len = self
+            .elems
+            .iter()
+            .enumerate()
+            .rev()
+            .find(|(_, &byte)| byte != 0)
+            // Map `i` from byte index to bit level index.
+            // `(i + 1) * 8` = Last bit in byte.
+            // `last - byte.leading_zeros()` = last set bit in byte.
+            // `as usize` won't ever truncate as the potential range is `0..=8`.
+            .map(|(i, byte)| ((i + 1) * 8) - byte.leading_zeros() as usize)
+            .unwrap_or(0);
+
+        Some(K::new(last_index))
+    }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use core::u32;
 
     // `EntityRef` impl for testing.
-    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
     struct E(u32);
 
     impl EntityRef for E {
         fn new(i: usize) -> Self {
             E(i as u32)
         }
         fn index(self) -> usize {
             self.0 as usize
@@ -154,9 +192,56 @@ mod tests {
         assert!(!m.contains(E(16)));
         assert!(!m.contains(E(19)));
         assert!(!m.contains(E(20)));
         assert!(!m.contains(E(u32::MAX)));
 
         m.clear();
         assert!(m.is_empty());
     }
+
+    #[test]
+    fn pop_ordered() {
+        let r0 = E(0);
+        let r1 = E(1);
+        let r2 = E(2);
+        let mut m = EntitySet::new();
+        m.insert(r0);
+        m.insert(r1);
+        m.insert(r2);
+
+        assert_eq!(r2, m.pop().unwrap());
+        assert_eq!(r1, m.pop().unwrap());
+        assert_eq!(r0, m.pop().unwrap());
+        assert!(m.pop().is_none());
+        assert!(m.pop().is_none());
+    }
+
+    #[test]
+    fn pop_unordered() {
+        let mut ebbs = [
+            E(0),
+            E(1),
+            E(6),
+            E(7),
+            E(5),
+            E(9),
+            E(10),
+            E(2),
+            E(3),
+            E(11),
+            E(12),
+        ];
+
+        let mut m = EntitySet::new();
+        for &ebb in &ebbs {
+            m.insert(ebb);
+        }
+        assert_eq!(m.len, 13);
+        ebbs.sort();
+
+        for &ebb in ebbs.iter().rev() {
+            assert_eq!(ebb, m.pop().unwrap());
+        }
+
+        assert!(m.is_empty());
+    }
 }
--- a/third_party/rust/cranelift-frontend/.cargo-checksum.json
+++ b/third_party/rust/cranelift-frontend/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"d3ad74a39dc6d5efeb4c02171789e53f50b2ecbe34d4bd6dcfc7856b52e50be5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"3d306290ac5fa2f42cb97c5bae00b9baeefcbf20a911b1c3cd90ddcaaefe2bfe","src/lib.rs":"0e75d619694313f8f44d648ecffe18197844906aba7a1e3b8bb179c9c2389aa6","src/ssa.rs":"ca882f303e0ac8a269e77e511d657115fcb2bf739315dea43ee7828921048512","src/switch.rs":"5c540b9f0e5b805b9962c0079fec722fa63ad68d93fae1986fbc65e9cf15d16a","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"d664b9c245e2c8985efb57a604bd937b945549a3725d25f9e3825567dfb7946e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"3d306290ac5fa2f42cb97c5bae00b9baeefcbf20a911b1c3cd90ddcaaefe2bfe","src/lib.rs":"0e75d619694313f8f44d648ecffe18197844906aba7a1e3b8bb179c9c2389aa6","src/ssa.rs":"ca882f303e0ac8a269e77e511d657115fcb2bf739315dea43ee7828921048512","src/switch.rs":"5c540b9f0e5b805b9962c0079fec722fa63ad68d93fae1986fbc65e9cf15d16a","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-frontend/Cargo.toml
+++ b/third_party/rust/cranelift-frontend/Cargo.toml
@@ -1,22 +1,22 @@
 [package]
 authors = ["The Cranelift Project Developers"]
 name = "cranelift-frontend"
-version = "0.42.0"
+version = "0.44.0"
 description = "Cranelift IR builder helper"
 license = "Apache-2.0 WITH LLVM-exception"
 documentation = "https://cranelift.readthedocs.io/"
 categories = ["no-std"]
 repository = "https://github.com/CraneStation/cranelift"
 readme = "README.md"
 edition = "2018"
 
 [dependencies]
-cranelift-codegen = { path = "../cranelift-codegen", version = "0.42.0", default-features = false }
+cranelift-codegen = { path = "../cranelift-codegen", version = "0.44.0", default-features = false }
 target-lexicon = "0.8.1"
 log = { version = "0.4.6", default-features = false }
 hashmap_core = { version = "0.1.9", optional = true }
 smallvec = { version = "0.6.10" }
 
 [features]
 default = ["std"]
 std = ["cranelift-codegen/std"]
--- a/third_party/rust/cranelift-wasm/.cargo-checksum.json
+++ b/third_party/rust/cranelift-wasm/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"3a4cfc0e561c29c298b550e6681a10a8bd99d5d33503604f9cb422c4f52831d3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"cb28478d7fc02ad68e82e52a80524a81db50463da982b23ce03abe1e7b50560f","src/environ/dummy.rs":"848079947623af4227935cfc980a8dfad03d314e9fa7408ee8a520a1043b68c8","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"d3363a0989ee2c31d5d31d7bd74d0bb23c3ae3b838b56661749f1f33ef986523","src/func_translator.rs":"2f1a80ede583cb14cfc2714c1d96855d6d0fdc5e044e092b0257179cd118d876","src/lib.rs":"43a29f5dfb3f3f0d3cf85a89eee68e699aae2f80252c09b62b56673c763a1c74","src/module_translator.rs":"7d41cd6b8c09eab6b9448cba46cc4c2f843ed6952b393338d257d5629dabfd62","src/sections_translator.rs":"e49fed0596052b82d0e0010d1fcfdf52e214a16a3aeaa8e57e871927b522c77d","src/state.rs":"fc2a8d468b4b681d9262fdb8762f3300ffce709cb0b2e48f3835a5b9164e7c93","src/translation_utils.rs":"aae22673eb5227840a225c9af831e68a272c6b2ad1300f54c3f0a6116ce88a65","tests/wasm_testsuite.rs":"fc3c9c7b7b504b199cb524b29a18e633f68704de289c865049496ac636c38e0b"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"70f4c05be2e949e3f35c6c2e7990af6802916ded9e4017b679dc988079b621c2","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"090fea0cff980468f423b1ea63a7cb1d8c4bf8349b588f577a700c90aa70a6c2","src/environ/dummy.rs":"848079947623af4227935cfc980a8dfad03d314e9fa7408ee8a520a1043b68c8","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"00911480a1eb3c85d635a197ff833e5180936364b2f61f9215f545b06829f362","src/func_translator.rs":"8f921c722f3e6b18c52a72e96d916b4f990bcdd42228e5be0ce3f182acc0eccb","src/lib.rs":"9c77bfa21596b8336e628e7808cde8cf167bbf1462b8f98abc6eddf90b1215d4","src/module_translator.rs":"c5d7506fffaf8f9034265273dad38983c898915cc7dbf445c659637b4838a3d3","src/sections_translator.rs":"55d0c1998f8007a559e7b3edd1c1fb3424f28596816fc0564acc2aae0dc08f3f","src/state.rs":"f7003dc78fdbb82c5c78188da1dca0bfcc0d907424dbdaa8a246184427850516","src/translation_utils.rs":"4b871e496e5bffc23e7094da01aa5d4cfa901e530e7d45f876e2c5bbe2ed897e","tests/wasm_testsuite.rs":"fc3c9c7b7b504b199cb524b29a18e633f68704de289c865049496ac636c38e0b"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-wasm/Cargo.toml
+++ b/third_party/rust/cranelift-wasm/Cargo.toml
@@ -1,25 +1,25 @@
 [package]
 name = "cranelift-wasm"
-version = "0.42.0"
+version = "0.44.0"
 authors = ["The Cranelift Project Developers"]
 description = "Translator from WebAssembly to Cranelift IR"
 repository = "https://github.com/CraneStation/cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
 categories = ["no-std", "wasm"]
 readme = "README.md"
 keywords = ["webassembly", "wasm"]
 edition = "2018"
 
 [dependencies]
-wasmparser = { version = "0.37.0", default-features = false }
-cranelift-codegen = { path = "../cranelift-codegen", version = "0.42.0", default-features = false }
-cranelift-entity = { path = "../cranelift-entity", version = "0.42.0", default-features = false }
-cranelift-frontend = { path = "../cranelift-frontend", version = "0.42.0", default-features = false }
+wasmparser = { version = "0.39.1", default-features = false }
+cranelift-codegen = { path = "../cranelift-codegen", version = "0.44.0", default-features = false }
+cranelift-entity = { path = "../cranelift-entity", version = "0.44.0", default-features = false }
+cranelift-frontend = { path = "../cranelift-frontend", version = "0.44.0", default-features = false }
 hashmap_core = { version = "0.1.9", optional = true }
 failure = { version = "0.1.1", default-features = false, features = ["derive"] }
 failure_derive = { version = "0.1.1", default-features = false }
 log = { version = "0.4.6", default-features = false }
 serde = { version = "1.0.94", features = ["derive"], optional = true }
 
 [dev-dependencies]
 wabt = "0.9.1"
--- a/third_party/rust/cranelift-wasm/src/code_translator.rs
+++ b/third_party/rust/cranelift-wasm/src/code_translator.rs
@@ -902,30 +902,30 @@ pub fn translate_operator<FE: FuncEnviro
         | Operator::I32AtomicRmwCmpxchg { .. }
         | Operator::I64AtomicRmwCmpxchg { .. }
         | Operator::I32AtomicRmw8UCmpxchg { .. }
         | Operator::I32AtomicRmw16UCmpxchg { .. }
         | Operator::I64AtomicRmw8UCmpxchg { .. }
         | Operator::I64AtomicRmw16UCmpxchg { .. }
         | Operator::I64AtomicRmw32UCmpxchg { .. }
         | Operator::Fence { .. } => {
-            wasm_unsupported!("proposed thread operator {:?}", op);
+            retu