Bug 1505777: Run mach-vendor-rust to update Cranelift. rs=bbouvier
☠☠ backed out by c8811545863b ☠ ☠
authorDan Gohman <sunfish@mozilla.com>
Thu, 08 Nov 2018 09:19:00 +0200
changeset 445246 027bf8dee1e5bd49a0781a18e3b7d39051d70d6c
parent 445245 29649174d3e73035afe853170fd3b37995138c7f
child 445247 f1e6ccbef48d843bff32d5b1c6d222041de98436
push id109705
push userncsoregi@mozilla.com
push dateThu, 08 Nov 2018 22:21:52 +0000
treeherdermozilla-inbound@f1e6ccbef48d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1505777
milestone65.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 1505777: Run mach-vendor-rust to update Cranelift. rs=bbouvier
Cargo.lock
third_party/rust/cranelift-bforest/.cargo-checksum.json
third_party/rust/cranelift-bforest/Cargo.toml
third_party/rust/cranelift-bforest/LICENSE
third_party/rust/cranelift-bforest/src/lib.rs
third_party/rust/cranelift-bforest/src/map.rs
third_party/rust/cranelift-bforest/src/node.rs
third_party/rust/cranelift-bforest/src/path.rs
third_party/rust/cranelift-bforest/src/pool.rs
third_party/rust/cranelift-bforest/src/set.rs
third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
third_party/rust/cranelift-codegen-meta/Cargo.toml
third_party/rust/cranelift-codegen-meta/LICENSE
third_party/rust/cranelift-codegen-meta/src/cdsl/isa.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs
third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs
third_party/rust/cranelift-codegen-meta/src/gen_registers.rs
third_party/rust/cranelift-codegen-meta/src/gen_types.rs
third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs
third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs
third_party/rust/cranelift-codegen-meta/src/isa/mod.rs
third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs
third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs
third_party/rust/cranelift-codegen-meta/src/lib.rs
third_party/rust/cranelift-codegen-meta/src/srcgen.rs
third_party/rust/cranelift-codegen/.cargo-checksum.json
third_party/rust/cranelift-codegen/Cargo.toml
third_party/rust/cranelift-codegen/LICENSE
third_party/rust/cranelift-codegen/build.rs
third_party/rust/cranelift-codegen/meta-python/base/formats.py
third_party/rust/cranelift-codegen/meta-python/base/instructions.py
third_party/rust/cranelift-codegen/meta-python/base/legalize.py
third_party/rust/cranelift-codegen/meta-python/base/settings.py
third_party/rust/cranelift-codegen/meta-python/base/types.py
third_party/rust/cranelift-codegen/meta-python/build.py
third_party/rust/cranelift-codegen/meta-python/cdsl/ast.py
third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py
third_party/rust/cranelift-codegen/meta-python/cdsl/isa.py
third_party/rust/cranelift-codegen/meta-python/cdsl/predicates.py
third_party/rust/cranelift-codegen/meta-python/cdsl/registers.py
third_party/rust/cranelift-codegen/meta-python/cdsl/test_ti.py
third_party/rust/cranelift-codegen/meta-python/cdsl/ti.py
third_party/rust/cranelift-codegen/meta-python/cdsl/types.py
third_party/rust/cranelift-codegen/meta-python/cdsl/typevar.py
third_party/rust/cranelift-codegen/meta-python/cdsl/xform.py
third_party/rust/cranelift-codegen/meta-python/gen_encoding.py
third_party/rust/cranelift-codegen/meta-python/gen_instr.py
third_party/rust/cranelift-codegen/meta-python/gen_registers.py
third_party/rust/cranelift-codegen/meta-python/gen_types.py
third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/recipes.py
third_party/rust/cranelift-codegen/meta-python/isa/x86/registers.py
third_party/rust/cranelift-codegen/meta-python/semantics/__init__.py
third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
third_party/rust/cranelift-codegen/src/binemit/mod.rs
third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
third_party/rust/cranelift-codegen/src/binemit/shrink.rs
third_party/rust/cranelift-codegen/src/cfg_printer.rs
third_party/rust/cranelift-codegen/src/context.rs
third_party/rust/cranelift-codegen/src/cursor.rs
third_party/rust/cranelift-codegen/src/dominator_tree.rs
third_party/rust/cranelift-codegen/src/flowgraph.rs
third_party/rust/cranelift-codegen/src/ir/builder.rs
third_party/rust/cranelift-codegen/src/ir/dfg.rs
third_party/rust/cranelift-codegen/src/ir/extfunc.rs
third_party/rust/cranelift-codegen/src/ir/function.rs
third_party/rust/cranelift-codegen/src/ir/globalvalue.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/jumptable.rs
third_party/rust/cranelift-codegen/src/ir/layout.rs
third_party/rust/cranelift-codegen/src/ir/libcall.rs
third_party/rust/cranelift-codegen/src/ir/memflags.rs
third_party/rust/cranelift-codegen/src/ir/mod.rs
third_party/rust/cranelift-codegen/src/ir/stackslot.rs
third_party/rust/cranelift-codegen/src/ir/types.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/call_conv.rs
third_party/rust/cranelift-codegen/src/isa/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/encoding.rs
third_party/rust/cranelift-codegen/src/isa/mod.rs
third_party/rust/cranelift-codegen/src/isa/registers.rs
third_party/rust/cranelift-codegen/src/isa/riscv/enc_tables.rs
third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
third_party/rust/cranelift-codegen/src/isa/x86/abi.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/boundary.rs
third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
third_party/rust/cranelift-codegen/src/legalizer/mod.rs
third_party/rust/cranelift-codegen/src/lib.rs
third_party/rust/cranelift-codegen/src/loop_analysis.rs
third_party/rust/cranelift-codegen/src/postopt.rs
third_party/rust/cranelift-codegen/src/predicates.rs
third_party/rust/cranelift-codegen/src/preopt.rs
third_party/rust/cranelift-codegen/src/print_errors.rs
third_party/rust/cranelift-codegen/src/regalloc/coloring.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/reload.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/simple_gvn.rs
third_party/rust/cranelift-codegen/src/simple_preopt.rs
third_party/rust/cranelift-codegen/src/timing.rs
third_party/rust/cranelift-codegen/src/topo_order.rs
third_party/rust/cranelift-codegen/src/verifier/flags.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/LICENSE
third_party/rust/cranelift-entity/README.md
third_party/rust/cranelift-entity/src/lib.rs
third_party/rust/cranelift-entity/src/list.rs
third_party/rust/cranelift-entity/src/map.rs
third_party/rust/cranelift-entity/src/primary.rs
third_party/rust/cranelift-entity/src/set.rs
third_party/rust/cranelift-entity/src/sparse.rs
third_party/rust/cranelift-frontend/.cargo-checksum.json
third_party/rust/cranelift-frontend/Cargo.toml
third_party/rust/cranelift-frontend/LICENSE
third_party/rust/cranelift-frontend/src/frontend.rs
third_party/rust/cranelift-frontend/src/lib.rs
third_party/rust/cranelift-frontend/src/ssa.rs
third_party/rust/cranelift-frontend/src/switch.rs
third_party/rust/cranelift-wasm/.cargo-checksum.json
third_party/rust/cranelift-wasm/Cargo.toml
third_party/rust/cranelift-wasm/LICENSE
third_party/rust/cranelift-wasm/src/code_translator.rs
third_party/rust/cranelift-wasm/src/environ/dummy.rs
third_party/rust/cranelift-wasm/src/environ/mod.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/cranelift-wasm/tests/wasm_testsuite.rs
third_party/rust/failure/.cargo-checksum.json
third_party/rust/failure/Cargo.toml
third_party/rust/failure/RELEASES.md
third_party/rust/failure/book/src/SUMMARY.md
third_party/rust/failure/book/src/fail.md
third_party/rust/failure/book/src/string-custom-error.md
third_party/rust/failure/examples/error_as_cause.rs
third_party/rust/failure/examples/string_custom_error_pattern.rs
third_party/rust/failure/src/as_fail.rs
third_party/rust/failure/src/context.rs
third_party/rust/failure/src/error/error_impl.rs
third_party/rust/failure/src/error/mod.rs
third_party/rust/failure/src/lib.rs
third_party/rust/failure/src/macros.rs
third_party/rust/failure_derive/.cargo-checksum.json
third_party/rust/failure_derive/Cargo.toml
third_party/rust/failure_derive/src/lib.rs
third_party/rust/synstructure/.cargo-checksum.json
third_party/rust/synstructure/Cargo.toml
third_party/rust/synstructure/src/lib.rs
third_party/rust/synstructure/src/macros.rs
third_party/rust/target-lexicon/.cargo-checksum.json
third_party/rust/target-lexicon/Cargo.toml
third_party/rust/target-lexicon/LICENSE
third_party/rust/target-lexicon/src/lib.rs
third_party/rust/target-lexicon/src/targets.rs
third_party/rust/target-lexicon/src/triple.rs
third_party/rust/wasmparser/.cargo-checksum.json
third_party/rust/wasmparser/Cargo.toml
third_party/rust/wasmparser/LICENSE
third_party/rust/wasmparser/check-rustfmt.sh
third_party/rust/wasmparser/examples/dump.rs
third_party/rust/wasmparser/examples/simple.rs
third_party/rust/wasmparser/format-all.sh
third_party/rust/wasmparser/src/binary_reader.rs
third_party/rust/wasmparser/src/lib.rs
third_party/rust/wasmparser/src/parser.rs
third_party/rust/wasmparser/src/primitives.rs
third_party/rust/wasmparser/src/readers/code_section.rs
third_party/rust/wasmparser/src/readers/data_section.rs
third_party/rust/wasmparser/src/readers/element_section.rs
third_party/rust/wasmparser/src/readers/export_section.rs
third_party/rust/wasmparser/src/readers/function_section.rs
third_party/rust/wasmparser/src/readers/global_section.rs
third_party/rust/wasmparser/src/readers/import_section.rs
third_party/rust/wasmparser/src/readers/init_expr.rs
third_party/rust/wasmparser/src/readers/linking_section.rs
third_party/rust/wasmparser/src/readers/memory_section.rs
third_party/rust/wasmparser/src/readers/mod.rs
third_party/rust/wasmparser/src/readers/module.rs
third_party/rust/wasmparser/src/readers/name_section.rs
third_party/rust/wasmparser/src/readers/operators.rs
third_party/rust/wasmparser/src/readers/reloc_section.rs
third_party/rust/wasmparser/src/readers/section_reader.rs
third_party/rust/wasmparser/src/readers/sourcemappingurl_section.rs
third_party/rust/wasmparser/src/readers/start_section.rs
third_party/rust/wasmparser/src/readers/table_section.rs
third_party/rust/wasmparser/src/readers/type_section.rs
third_party/rust/wasmparser/src/tests.rs
third_party/rust/wasmparser/src/validator.rs
third_party/rust/wasmparser/test-all.sh
third_party/rust/wasmparser/test-no_std.sh
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -156,21 +156,21 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "baldrdash"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.43.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "base64"
 version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -452,67 +452,71 @@ 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.20.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-entity 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.20.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cranelift-bforest 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-bforest 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen-meta 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-entity 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.20.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cranelift-entity 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.20.1"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.20.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.20.1"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-codegen 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-entity 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cranelift-frontend 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasmparser 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasmparser 0.21.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "crc"
 version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -839,32 +843,32 @@ version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "failure"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "failure_derive"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "fake-simd"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -2014,17 +2018,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "redox_users"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "regex"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2063,17 +2067,17 @@ dependencies = [
 
 [[package]]
 name = "rkv"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lmdb-rkv 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2485,32 +2489,32 @@ dependencies = [
  "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "synstructure"
-version = "0.9.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "target-lexicon"
-version = "0.0.3"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
  "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "tempdir"
 version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -2890,17 +2894,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "wasmparser"
-version = "0.17.2"
+version = "0.21.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "webdriver"
 version = "0.38.0"
 dependencies = [
  "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3157,22 +3161,22 @@ dependencies = [
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
 "checksum core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7caa6cb9e76ddddbea09a03266d6b3bc98cd41e9fb9b017c473e7cca593ec25"
 "checksum core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2a53cce0ddcf7e7e1f998738d757d5a3bf08bf799a180e50ebe50d298f52f5a"
 "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.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96851b525021dd220259b9f29bf79d83f65b49e4f12b786d545aa929e4cad2"
-"checksum cranelift-codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16f418f1d1e6221812a7d35cff5b9a572dc978c002e33792134bbd50c07cacca"
-"checksum cranelift-codegen-meta 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1da3daa0109e7a0b7b322cea666cc223fb6a0d5170e83d23b3d5d2deaddca5f3"
-"checksum cranelift-entity 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27412f153f2b517125dea9247ee8859a9ea3923d44384d54420e64fab9314752"
-"checksum cranelift-frontend 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03c44cc7006b375e60e0c7edb6fc81abfbf20158374c03f5d0da981b373860a3"
-"checksum cranelift-wasm 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a9d3454bf60ee6c3d1f54d6cf9ed82cfc1a2e7efb9ec1b16666bf2987c88bfa"
+"checksum cranelift-bforest 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5f8e1ab4f73b59a98531a8013d8ed3ca7edb4e36984cb301d9c06f6892787b"
+"checksum cranelift-codegen 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437ec8212686e6cdacfea75aaedb4ab8b013869be1e8693a4cb97a60f135035"
+"checksum cranelift-codegen-meta 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4eac16097b96e9f609df735555f2d1658531750fbc3805bca1daca7671aef9eb"
+"checksum cranelift-entity 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9be3f82369346201c2e0cff720522e6eb55459e51c916b2199f25cff2058ca96"
+"checksum cranelift-frontend 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5d18ab2bc89a09b4275442a9559dc0f947b9a8ad9ae9ee89452a057df54ced"
+"checksum cranelift-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5906a111814d43d84002ef974eb0c023804fd4d1866b34f43c1bb588a759ad8"
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
 "checksum cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "730363a45c4e248d4f21d3e5c1156d1a9cdec0855056c0d9539e814bc59865c3"
@@ -3196,18 +3200,18 @@ dependencies = [
 "checksum dwrote 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b5a0af6d47ecf67355dc36e5fc09547050bd8a4b87870e637911ffe4aced32a"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
 "checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621"
 "checksum encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "769ecb8b33323998e482b218c0d13cd64c267609023b4b7ec3ee740714c318ee"
 "checksum encoding_rs 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a79fa56c329a5b087de13748054fb3b974c4a672c12c71f0b66e35c5addec5"
 "checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
 "checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f"
-"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
-"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
+"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
+"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596"
 "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 "checksum fixedbitset 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "85cb8fec437468d86dc7c83ca7cfc933341d561873275f22dd5eedefa63a6478"
 "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ebc04f19019fff1f2d627b5581574ead502f80c48c88900575a46e0840fe5d0"
 "checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
 "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
@@ -3342,19 +3346,19 @@ dependencies = [
 "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
 "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
 "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
 "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
 "checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d"
 "checksum syn 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)" = "455a6ec9b368f8c479b0ae5494d13b22dc00990d2f00d68c9dc6a2dc4f17f210"
+"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
 "checksum synstructure 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "98cad891cd238c98e1f0aec9f7c0f620aa696e4e5f7daba56ac67b5e86a6b049"
-"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
-"checksum target-lexicon 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a34226bd63b5a26fc909f5f0d7ef4dc55d5851077035e49437e4e14bf567247f"
+"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
 "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
 "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
 "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
 "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
 "checksum thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73fdf4b84c65a85168477b7fb6c498e0716bc9487fba24623389ea7f51708044"
@@ -3387,17 +3391,17 @@ dependencies = [
 "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
 "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 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 wasmparser 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fed18a63a6796175be2254fccca1da4e8b8fec0abca37ad155aea345feb50798"
+"checksum wasmparser 0.21.8 (registry+https://github.com/rust-lang/crates.io-index)" = "202e4cd4d99aa8adb8fe6280e099fdd2e5003c8d09c27de6969ff04dba60ef39"
 "checksum webidl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f807f7488d680893f7188aa09d7672a3a0a8461975a098a2edf0a52e3fee29"
 "checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb"
 "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-x86_64-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
--- 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":"2ac8519f0423d9cc23bc68fb13e4af52ba478dd31c49fdb4cd0a1bd3251d4a48","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"569333274dd318ddfe098a9962f353ca45d2702f9a44dfe8180f91c97fa19211","src/map.rs":"1d7882872863386c2576bfcb7c4caf2d135c250feadf82d342ad3682c64d9c7c","src/node.rs":"3943b6126f1b8f83421a9db073db880e80003d93458170a36195f06bad452be4","src/path.rs":"28e29259ff6a2ca35adc5a036bebede3f0da39d40c91de27d219ef04dd60f994","src/pool.rs":"d572863b0e2055b13ea4f34a06512778915a98bfe6f9073d3829d26108c506b0","src/set.rs":"879a7469b7f86fe90786945b19d3f85909a651fb9b297d660b4ce118d6718ec6"},"package":"1e96851b525021dd220259b9f29bf79d83f65b49e4f12b786d545aa929e4cad2"}
\ No newline at end of file
+{"files":{"Cargo.toml":"a9d64466eee85b2f607e61ad354cb7b08cc17b925395fb2ec08eec61726773e9","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"01f8c9b8a077975c8f0803f793b8c20b583aaef2dc1f4400b9d90ba132ff4133","src/map.rs":"77eb9fd2ffdaafaf4daea609602a0c775c5012efae21c03547f63653271da163","src/node.rs":"309609acc70f1ce6be2f3c964430d23c0680bd7a647afab837a2aedc06235531","src/path.rs":"25326bacbb99189e873cb70e770f21c13fdef0fb2cd20f484830386fc4c75c6a","src/pool.rs":"196216124922dc42708a3aa944e98b6a57ef9bb770dab7e01f154b6382cab021","src/set.rs":"d4ff99fe51de9eefb4c774e919259d952ab5dde4dd3b99bd9974e4eedbb28938"},"package":"8c5f8e1ab4f73b59a98531a8013d8ed3ca7edb4e36984cb301d9c06f6892787b"}
\ No newline at end of file
--- a/third_party/rust/cranelift-bforest/Cargo.toml
+++ b/third_party/rust/cranelift-bforest/Cargo.toml
@@ -7,27 +7,27 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cranelift-bforest"
-version = "0.20.0"
+version = "0.23.0"
 authors = ["The Cranelift Project Developers"]
 description = "A forest of B+-trees"
 documentation = "https://cranelift.readthedocs.io/"
 readme = "README.md"
 keywords = ["btree", "forest", "set", "map"]
 categories = ["no-std"]
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/CraneStation/cranelift"
 [dependencies.cranelift-entity]
-version = "0.20.0"
+version = "0.23.0"
 default-features = false
 
 [features]
 default = ["std"]
 std = ["cranelift-entity/std"]
 [badges.maintenance]
 status = "experimental"
 
--- a/third_party/rust/cranelift-bforest/LICENSE
+++ b/third_party/rust/cranelift-bforest/LICENSE
@@ -212,8 +212,9 @@ with the conditions of Sections 4(a), 4(
 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.
+
--- a/third_party/rust/cranelift-bforest/src/lib.rs
+++ b/third_party/rust/cranelift-bforest/src/lib.rs
@@ -11,23 +11,35 @@
 //! - Keys and values are expected to be small and copyable. We optimize for 32-bit types.
 //! - A comparator object is used to compare keys, allowing smaller "context free" keys.
 //! - Empty trees have a very small 32-bit footprint.
 //! - All the trees in a forest can be cleared in constant time.
 
 #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
 #![warn(unused_import_braces)]
 #![cfg_attr(feature = "std", warn(unstable_features))]
-#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
-#![cfg_attr(feature = "cargo-clippy", allow(new_without_default, new_without_default_derive))]
+#![cfg_attr(
+    feature = "clippy",
+    plugin(clippy(conf_file = "../../clippy.toml"))
+)]
+#![cfg_attr(
+    feature = "cargo-clippy",
+    allow(new_without_default, new_without_default_derive)
+)]
 #![cfg_attr(
     feature = "cargo-clippy",
     warn(
-        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
-        print_stdout, unicode_not_nfc, use_self
+        float_arithmetic,
+        mut_mut,
+        nonminimal_bool,
+        option_map_unwrap_or,
+        option_map_unwrap_or_else,
+        print_stdout,
+        unicode_not_nfc,
+        use_self
     )
 )]
 // Turns on no_std and alloc features if std is not available.
 #![cfg_attr(not(feature = "std"), no_std)]
 #![cfg_attr(not(feature = "std"), feature(alloc))]
 
 /// This replaces `std` in builds with `core`.
 #[cfg(not(feature = "std"))]
@@ -141,17 +153,17 @@ fn slice_insert<T: Copy>(s: &mut [T], i:
 /// Shift elements in `s` to the left by `n` positions.
 fn slice_shift<T: Copy>(s: &mut [T], n: usize) {
     for j in 0..s.len() - n {
         s[j] = s[j + n];
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use entity::EntityRef;
 
     /// An opaque reference to an extended basic block in a function.
     #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
     pub struct Ebb(u32);
     entity_impl!(Ebb, "ebb");
 
--- a/third_party/rust/cranelift-bforest/src/map.rs
+++ b/third_party/rust/cranelift-bforest/src/map.rs
@@ -261,38 +261,35 @@ where
 
 impl<'a, K, V, C> MapCursor<'a, K, V, C>
 where
     K: Copy,
     V: Copy,
     C: Comparator<K>,
 {
     /// Create a cursor with a default (off-the-end) location.
-    fn new(
-        container: &'a mut Map<K, V>,
-        forest: &'a mut MapForest<K, V>,
-        comp: &'a C,
-    ) -> MapCursor<'a, K, V, C> {
-        MapCursor {
+    fn new(container: &'a mut Map<K, V>, forest: &'a mut MapForest<K, V>, comp: &'a C) -> Self {
+        Self {
             root: &mut container.root,
             pool: &mut forest.nodes,
             comp,
             path: Path::default(),
         }
     }
 
     /// Is this cursor pointing to an empty map?
     pub fn is_empty(&self) -> bool {
         self.root.is_none()
     }
 
     /// Move cursor to the next key-value pair and return it.
     ///
     /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end
     /// position.
+    #[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
     pub fn next(&mut self) -> Option<(K, V)> {
         self.path.next(self.pool)
     }
 
     /// Move cursor to the previous key-value pair and return it.
     ///
     /// If the cursor is already pointing at the first entry, leave it there and return `None`.
     pub fn prev(&mut self) -> Option<(K, V)> {
@@ -424,17 +421,17 @@ where
     /// Get a text version of the path to the current position.
     fn tpath(&self) -> String {
         use std::string::ToString;
         self.path.to_string()
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::super::NodeData;
     use super::*;
     use std::mem;
     use std::vec::Vec;
 
     #[test]
     fn node_size() {
         // check that nodes are cache line sized when keys and values are 32 bits.
--- a/third_party/rust/cranelift-bforest/src/node.rs
+++ b/third_party/rust/cranelift-bforest/src/node.rs
@@ -100,17 +100,17 @@ impl<F: Forest> NodeData<F> {
             NodeData::Inner {
                 size,
                 ref keys,
                 ref tree,
             } => {
                 let size = usize::from(size);
                 // TODO: We could probably use `get_unchecked()` here since `size` is always in
                 // range.
-                (&keys[0..size], &tree[0..size + 1])
+                (&keys[0..size], &tree[0..=size])
             }
             _ => panic!("Expected inner node"),
         }
     }
 
     /// Unwrap a leaf node into two slices (keys, values) of the same length.
     pub fn unwrap_leaf(&self) -> (&[F::Key], &[F::Value]) {
         match *self {
@@ -170,20 +170,20 @@ impl<F: Forest> NodeData<F> {
                 ref mut size,
                 ref mut keys,
                 ref mut tree,
             } => {
                 let sz = usize::from(*size);
                 debug_assert!(sz <= keys.len());
                 debug_assert!(index <= sz, "Can't insert at {} with {} keys", index, sz);
 
-                if let Some(ks) = keys.get_mut(0..sz + 1) {
+                if let Some(ks) = keys.get_mut(0..=sz) {
                     *size = (sz + 1) as u8;
                     slice_insert(ks, index, key);
-                    slice_insert(&mut tree[1..sz + 2], index, node);
+                    slice_insert(&mut tree[1..=sz + 1], index, node);
                     true
                 } else {
                     false
                 }
             }
             _ => panic!("Expected inner node"),
         }
     }
@@ -198,20 +198,20 @@ impl<F: Forest> NodeData<F> {
                 ref mut vals,
             } => {
                 let sz = usize::from(*size);
                 let keys = keys.borrow_mut();
                 let vals = vals.borrow_mut();
                 debug_assert!(sz <= keys.len());
                 debug_assert!(index <= sz);
 
-                if let Some(ks) = keys.get_mut(0..sz + 1) {
+                if let Some(ks) = keys.get_mut(0..=sz) {
                     *size = (sz + 1) as u8;
                     slice_insert(ks, index, key);
-                    slice_insert(&mut vals[0..sz + 1], index, value);
+                    slice_insert(&mut vals[0..=sz], index, value);
                     true
                 } else {
                     false
                 }
             }
             _ => panic!("Expected leaf node"),
         }
     }
@@ -577,17 +577,17 @@ where
             }
             NodeData::Free { next: Some(n) } => write!(f, "[ free -> {} ]", n),
             NodeData::Free { next: None } => write!(f, "[ free ]"),
         }
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use std::mem;
     use std::string::ToString;
 
     // Forest impl for a set implementation.
     struct TF();
 
     impl Forest for TF {
--- a/third_party/rust/cranelift-bforest/src/path.rs
+++ b/third_party/rust/cranelift-bforest/src/path.rs
@@ -698,17 +698,17 @@ impl<F: Forest> fmt::Display for Path<F>
                 write!(f, "--{}[{}]", self.node[i], self.entry[i])?;
             }
             Ok(())
         }
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::super::{Forest, NodeData, NodePool};
     use super::*;
     use std::cmp::Ordering;
 
     struct TC();
 
     impl Comparator<i32> for TC {
         fn cmp(&self, a: i32, b: i32) -> Ordering {
--- a/third_party/rust/cranelift-bforest/src/pool.rs
+++ b/third_party/rust/cranelift-bforest/src/pool.rs
@@ -85,17 +85,17 @@ impl<F: Forest> NodePool<F> {
     {
         use entity::SparseSet;
         use std::borrow::Borrow;
         use std::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] {
+        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 todo = Vec::new();
 
         // Todo-list entries are:
         // 1. Optional LHS key which must be <= all node entries.
--- a/third_party/rust/cranelift-bforest/src/set.rs
+++ b/third_party/rust/cranelift-bforest/src/set.rs
@@ -202,38 +202,35 @@ where
 }
 
 impl<'a, K, C> SetCursor<'a, K, C>
 where
     K: Copy,
     C: Comparator<K>,
 {
     /// Create a cursor with a default (invalid) location.
-    fn new(
-        container: &'a mut Set<K>,
-        forest: &'a mut SetForest<K>,
-        comp: &'a C,
-    ) -> SetCursor<'a, K, C> {
-        SetCursor {
+    fn new(container: &'a mut Set<K>, forest: &'a mut SetForest<K>, comp: &'a C) -> Self {
+        Self {
             root: &mut container.root,
             pool: &mut forest.nodes,
             comp,
             path: Path::default(),
         }
     }
 
     /// Is this cursor pointing to an empty set?
     pub fn is_empty(&self) -> bool {
         self.root.is_none()
     }
 
     /// Move cursor to the next element and return it.
     ///
     /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end
     /// position.
+    #[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
     pub fn next(&mut self) -> Option<K> {
         self.path.next(self.pool).map(|(k, _)| k)
     }
 
     /// Move cursor to the previous element and return it.
     ///
     /// If the cursor is already pointing at the first element, leave it there and return `None`.
     pub fn prev(&mut self) -> Option<K> {
@@ -352,17 +349,17 @@ where
         match self.root.take() {
             Some(root) => Some(self.path.first(root, self.pool).0),
             None => self.path.next(self.pool).map(|(k, _)| k),
         }
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::super::NodeData;
     use super::*;
     use std::mem;
     use std::vec::Vec;
 
     #[test]
     fn node_size() {
         // check that nodes are cache line sized when keys are 32 bits.
--- 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":"410de243e172b6d8597ca3cf2d2e8da264762966755ccd4d99496ba4b4034a98","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/base/mod.rs":"9320dfed2250bdb0347e01862b2ff7bf7db78920dae1719834b374de11131e87","src/base/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/cdsl/mod.rs":"1ed81ef8c6bc01384a840fa01f434c20ddd6c90ba10cdc5dc8b39dab7c647a70","src/cdsl/types.rs":"53e9f0e6d9c2cf0321a0c02324c0408fc14b01d1d3c16771f133169d57ff7a19","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_types.rs":"4b6be1877ce80205bdda954a0e7d4c04083d35811f3907619be18475a005eed3","src/lib.rs":"b6fc7d24e86439a5d62a0662865bf937e921fd6607cbabda616445a7219ec2f5","src/srcgen.rs":"3e6874cb3cb1155dc10ee9043b2a7ca4dfc3373d1079a864f931fc54aa325c9d"},"package":"1da3daa0109e7a0b7b322cea666cc223fb6a0d5170e83d23b3d5d2deaddca5f3"}
\ No newline at end of file
+{"files":{"Cargo.toml":"56d43cc835cbea830d3659c9f32062f3413c85a0eba618acc633fe0f6640445d","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/base/mod.rs":"9320dfed2250bdb0347e01862b2ff7bf7db78920dae1719834b374de11131e87","src/base/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/cdsl/isa.rs":"52ab00f489acbf00ebda8e2866de6495f3ed0f57d06896418dc7a2e8def902d2","src/cdsl/mod.rs":"311726d7e4ad9278eab301fd4f6e31e697b7d4260733c6a00fe39cd61db977d3","src/cdsl/regs.rs":"fe24d2ea67d7eec9912c2f9c85bbec98a12c43c9a1dd12f219795abf2e8d962a","src/cdsl/types.rs":"f9756e483329f00a1d8a15e30bc05e8d4c8fa71ff1f649b808528ddeb5fbdfea","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_registers.rs":"3d38ff5b0c6183209d4ba84bd1f14b1d84bea697c0589471aa5ce4abc209f20b","src/gen_types.rs":"5eb4e9bd0fda7f7644bb2428045f0bf16f2b698ff32cadcbbf7f2c7669f18de3","src/isa/arm32/mod.rs":"2a1aef09ead88fac19ca65f0ca01b5b38761001f7816984300d640001d818f33","src/isa/arm64/mod.rs":"5b034bcdcef2ab161c43afa860c7f176c81647f076c47cc4315917e13aa47810","src/isa/mod.rs":"927e5543dbe5c22bd6356b252318942ca16e3cbce466641a4f494a8a492443d9","src/isa/riscv/mod.rs":"f691fd37f2770919b32725ae0a2b523bc231aebb4aada4f9a591fc2acbbb2dc7","src/isa/x86/mod.rs":"0821384e048456475061c69f94a2f96868311114c18c758b841720c76f6daa71","src/lib.rs":"dd97d73d41ffee2d2cc62705f9f6f7ed6b9af982aff8d1fafb72590e097c513c","src/srcgen.rs":"abe118fb41a643ffc63577cc4b62de9a2286e1eeb34b95bff79648d0ea582886"},"package":"4eac16097b96e9f609df735555f2d1658531750fbc3805bca1daca7671aef9eb"}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen-meta/Cargo.toml
+++ b/third_party/rust/cranelift-codegen-meta/Cargo.toml
@@ -7,19 +7,21 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cranelift-codegen-meta"
-version = "0.20.0"
+version = "0.23.0"
 authors = ["The Cranelift Project Developers"]
 description = "Metaprogram for cranelift-codegen code generator library"
 readme = "README.md"
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/CraneStation/cranelift"
+[dependencies.cranelift-entity]
+version = "0.23.0"
 [badges.maintenance]
 status = "experimental"
 
 [badges.travis-ci]
 repository = "CraneStation/cranelift"
--- a/third_party/rust/cranelift-codegen-meta/LICENSE
+++ b/third_party/rust/cranelift-codegen-meta/LICENSE
@@ -212,8 +212,9 @@ with the conditions of Sections 4(a), 4(
 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-meta/src/cdsl/isa.rs
@@ -0,0 +1,142 @@
+use cranelift_entity::PrimaryMap;
+
+use super::regs::{
+    RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex,
+};
+
+pub struct TargetIsa {
+    pub name: &'static str,
+    pub reg_banks: PrimaryMap<RegBankIndex, RegBank>,
+    pub reg_classes: PrimaryMap<RegClassIndex, RegClass>,
+}
+
+impl TargetIsa {
+    pub fn new(name: &'static str) -> Self {
+        Self {
+            name,
+            reg_banks: PrimaryMap::new(),
+            reg_classes: PrimaryMap::new(),
+        }
+    }
+
+    pub fn add_reg_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
+        let first_unit = if self.reg_banks.len() == 0 {
+            0
+        } else {
+            let last = &self.reg_banks.last().unwrap();
+            let first_available_unit = (last.first_unit + last.units) as i8;
+            let units = builder.units;
+            let align = if units.is_power_of_two() {
+                units
+            } else {
+                units.next_power_of_two()
+            } as i8;
+            (first_available_unit + align - 1) & -align
+        } as u8;
+
+        self.reg_banks.push(RegBank::new(
+            builder.name,
+            first_unit,
+            builder.units,
+            builder.names,
+            builder.prefix,
+            builder
+                .pressure_tracking
+                .expect("Pressure tracking must be explicitly set"),
+        ))
+    }
+
+    pub fn add_reg_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
+        let reg_bank_units = self.reg_banks.get(builder.bank).unwrap().units;
+
+        let start = builder.start;
+        assert!(start < reg_bank_units);
+
+        let count = if builder.count != 0 {
+            builder.count
+        } else {
+            reg_bank_units / builder.width
+        };
+
+        let reg_class_index = builder.index;
+        assert!(
+            self.reg_classes.next_key() == reg_class_index,
+            "should have inserted RegClass where expected"
+        );
+
+        let reg_class = RegClass::new(
+            builder.name,
+            reg_class_index,
+            builder.width,
+            builder.bank,
+            builder.toprc,
+            count,
+            start,
+        );
+        self.reg_classes.push(reg_class);
+
+        let reg_bank = self.reg_banks.get_mut(builder.bank).unwrap();
+        reg_bank.classes.push(reg_class_index);
+
+        reg_class_index
+    }
+
+    /// Checks that the set of register classes satisfies:
+    ///
+    /// 1. Closed under intersection: The intersection of any two register
+    ///    classes in the set is either empty or identical to a member of the
+    ///    set.
+    /// 2. There are no identical classes under different names.
+    /// 3. Classes are sorted topologically such that all subclasses have a
+    ///    higher index that the superclass.
+    pub fn check(&self) {
+        for reg_bank in self.reg_banks.values() {
+            for i1 in reg_bank.classes.iter() {
+                for i2 in reg_bank.classes.iter() {
+                    if i1 >= i2 {
+                        continue;
+                    }
+
+                    let rc1 = self.reg_classes.get(*i1).unwrap();
+                    let rc2 = self.reg_classes.get(*i2).unwrap();
+
+                    let rc1_mask = rc1.mask(0);
+                    let rc2_mask = rc2.mask(0);
+
+                    assert!(
+                        rc1.width != rc2.width || rc1_mask != rc2_mask,
+                        "no duplicates"
+                    );
+                    if rc1.width != rc2.width {
+                        continue;
+                    }
+
+                    let mut intersect = Vec::new();
+                    for (a, b) in rc1_mask.iter().zip(rc2_mask.iter()) {
+                        intersect.push(a & b);
+                    }
+                    if intersect == vec![0; intersect.len()] {
+                        continue;
+                    }
+
+                    // Classes must be topologically ordered, so the intersection can't be the
+                    // superclass.
+                    assert!(intersect != rc1_mask);
+
+                    // If the intersection is the second one, then it must be a subclass.
+                    if intersect == rc2_mask {
+                        assert!(
+                            self.reg_classes
+                                .get(*i1)
+                                .unwrap()
+                                .subclasses
+                                .iter()
+                                .find(|x| **x == *i2)
+                                .is_some()
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/mod.rs
@@ -1,13 +1,15 @@
 //! Cranelift DSL classes.
 //!
 //! This module defines the classes that are used to define Cranelift
-//! instructions and other entitties.
+//! instructions and other entities.
 
+pub mod isa;
+pub mod regs;
 pub mod types;
 
 /// Convert the string `s` to CamelCase.
 fn _camel_case(s: &str) -> String {
     let mut output_chars = String::with_capacity(s.len());
 
     let mut capitalize = true;
     for curr_char in s.chars() {
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/regs.rs
@@ -0,0 +1,199 @@
+use cranelift_entity::EntityRef;
+
+use super::isa::TargetIsa;
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct RegBankIndex(u32);
+entity_impl!(RegBankIndex);
+
+pub struct RegBank {
+    pub name: &'static str,
+    pub first_unit: u8,
+    pub units: u8,
+    pub names: Vec<&'static str>,
+    pub prefix: &'static str,
+    pub pressure_tracking: bool,
+    pub toprcs: Vec<RegClassIndex>,
+    pub classes: Vec<RegClassIndex>,
+}
+
+impl RegBank {
+    pub fn new(
+        name: &'static str,
+        first_unit: u8,
+        units: u8,
+        names: Vec<&'static str>,
+        prefix: &'static str,
+        pressure_tracking: bool,
+    ) -> Self {
+        RegBank {
+            name,
+            first_unit,
+            units,
+            names,
+            prefix,
+            pressure_tracking,
+            toprcs: Vec::new(),
+            classes: Vec::new(),
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct RegClassIndex(u32);
+entity_impl!(RegClassIndex);
+
+pub struct RegClass {
+    pub name: &'static str,
+    pub index: RegClassIndex,
+    pub width: u8,
+    pub bank: RegBankIndex,
+    pub toprc: RegClassIndex,
+    pub count: u8,
+    pub start: u8,
+    pub subclasses: Vec<RegClassIndex>,
+}
+
+impl RegClass {
+    pub fn new(
+        name: &'static str,
+        index: RegClassIndex,
+        width: u8,
+        bank: RegBankIndex,
+        toprc: RegClassIndex,
+        count: u8,
+        start: u8,
+    ) -> Self {
+        Self {
+            name,
+            index,
+            width,
+            bank,
+            toprc,
+            count,
+            start,
+            subclasses: Vec::new(),
+        }
+    }
+
+    /// Compute a bit-mask of subclasses, including self.
+    pub fn subclass_mask(&self) -> u64 {
+        let mut m = 1 << self.index.index();
+        for rc in self.subclasses.iter() {
+            m |= 1 << rc.index();
+        }
+        m
+    }
+
+    /// Compute a bit-mask of the register units allocated by this register class.
+    pub fn mask(&self, bank_first_unit: u8) -> Vec<u32> {
+        let mut u = (self.start + bank_first_unit) as usize;
+        let mut out_mask = vec![0, 0, 0];
+        for _ in 0..self.count {
+            out_mask[u / 32] |= 1 << (u % 32);
+            u += self.width as usize;
+        }
+        out_mask
+    }
+}
+
+pub struct RegClassBuilder {
+    pub name: &'static str,
+    pub index: RegClassIndex,
+    pub width: u8,
+    pub bank: RegBankIndex,
+    pub toprc: RegClassIndex,
+    pub count: u8,
+    pub start: u8,
+}
+
+impl RegClassBuilder {
+    pub fn new_toplevel(isa: &mut TargetIsa, name: &'static str, bank: RegBankIndex) -> Self {
+        let index = isa.reg_classes.next_key();
+
+        // Add it to the top-level register classes of the register bank.
+        isa.reg_banks.get_mut(bank).unwrap().toprcs.push(index);
+
+        Self {
+            name,
+            index,
+            width: 1,
+            bank,
+            toprc: index,
+            count: 0,
+            start: 0,
+        }
+    }
+
+    pub fn subclass_of(
+        isa: &mut TargetIsa,
+        name: &'static str,
+        parent_index: RegClassIndex,
+        start: u8,
+        stop: u8,
+    ) -> Self {
+        assert!(stop >= start);
+
+        let index = isa.reg_classes.next_key();
+
+        let toprc = isa.reg_classes.get(parent_index).unwrap().toprc;
+        for reg_class in isa.reg_classes.values_mut() {
+            if reg_class.toprc == toprc {
+                reg_class.subclasses.push(index);
+            }
+        }
+
+        let parent = &isa.reg_classes.get(parent_index).unwrap();
+        Self {
+            name,
+            count: stop - start,
+            width: parent.width,
+            start: parent.start + start * parent.width,
+            bank: parent.bank,
+            toprc: parent.toprc,
+            index,
+        }
+    }
+
+    pub fn count(mut self, count: u8) -> Self {
+        self.count = count;
+        self
+    }
+
+    pub fn width(mut self, width: u8) -> Self {
+        self.width = width;
+        self
+    }
+}
+
+pub struct RegBankBuilder {
+    pub name: &'static str,
+    pub units: u8,
+    pub names: Vec<&'static str>,
+    pub prefix: &'static str,
+    pub pressure_tracking: Option<bool>,
+}
+
+impl RegBankBuilder {
+    pub fn new(name: &'static str, prefix: &'static str) -> Self {
+        Self {
+            name,
+            units: 0,
+            names: vec![],
+            prefix,
+            pressure_tracking: None,
+        }
+    }
+    pub fn units(mut self, units: u8) -> Self {
+        self.units = units;
+        self
+    }
+    pub fn names(mut self, names: Vec<&'static str>) -> Self {
+        self.names = names;
+        self
+    }
+    pub fn track_pressure(mut self, track: bool) -> Self {
+        self.pressure_tracking = Some(track);
+        self
+    }
+}
--- a/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/types.rs
@@ -74,39 +74,29 @@ impl ValueType {
         }
     }
 
     /// Find the number of bytes that this type occupies in memory.
     pub fn membytes(&self) -> u64 {
         self.width() / 8
     }
 
-    /// Get the name of this type.
-    pub fn name(&self) -> String {
-        match *self {
-            ValueType::BV(ref b) => b.name(),
-            ValueType::Lane(l) => l.name(),
-            ValueType::Special(s) => s.name(),
-            ValueType::Vector(ref v) => v.name(),
-        }
-    }
-
     /// Find the unique number associated with this type.
     pub fn number(&self) -> Option<u8> {
         match *self {
             ValueType::BV(_) => None,
             ValueType::Lane(l) => Some(l.number()),
             ValueType::Special(s) => Some(s.number()),
             ValueType::Vector(ref v) => Some(v.number()),
         }
     }
 
     /// Return the name of this type for generated Rust source files.
     pub fn _rust_name(&self) -> String {
-        format!("{}{}", _RUST_NAME_PREFIX, self.name().to_uppercase())
+        format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase())
     }
 
     /// Return true iff:
     ///     1. self and other have equal number of lanes
     ///     2. each lane in self has at least as many bits as a lane in other
     pub fn _wider_or_equal(&self, rhs: &ValueType) -> bool {
         (self.lane_count() == rhs.lane_count()) && (self.lane_bits() >= rhs.lane_bits())
     }
@@ -114,17 +104,22 @@ impl ValueType {
     /// Return the total number of bits of an instance of this type.
     pub fn width(&self) -> u64 {
         self.lane_count() * self.lane_bits()
     }
 }
 
 impl fmt::Display for ValueType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.name())
+        match *self {
+            ValueType::BV(ref b) => b.fmt(f),
+            ValueType::Lane(l) => l.fmt(f),
+            ValueType::Special(s) => s.fmt(f),
+            ValueType::Vector(ref v) => v.fmt(f),
+        }
     }
 }
 
 /// Create a ValueType from a given bitvector type.
 impl From<BVType> for ValueType {
     fn from(bv: BVType) -> Self {
         ValueType::BV(bv)
     }
@@ -156,18 +151,18 @@ impl From<VectorType> for ValueType {
 pub enum LaneType {
     BoolType(base_types::Bool),
     FloatType(base_types::Float),
     IntType(base_types::Int),
 }
 
 impl LaneType {
     /// Return a string containing the documentation comment for this lane type.
-    pub fn doc(&self) -> String {
-        match *self {
+    pub fn doc(self) -> String {
+        match self {
             LaneType::BoolType(_) => format!("A boolean type with {} bits.", self.lane_bits()),
             LaneType::FloatType(base_types::Float::F32) => String::from(
                 "A 32-bit floating point type represented in the IEEE 754-2008
                 *binary32* interchange format. This corresponds to the :c:type:`float`
                 type in most C implementations.",
             ),
             LaneType::FloatType(base_types::Float::F64) => String::from(
                 "A 64-bit floating point type represented in the IEEE 754-2008
@@ -180,51 +175,52 @@ impl LaneType {
                 self.lane_bits(),
                 self.lane_bits()
             ),
             LaneType::IntType(_) => format!("An integer type with {} bits.", self.lane_bits()),
         }
     }
 
     /// Return the number of bits in a lane.
-    pub fn lane_bits(&self) -> u64 {
-        match *self {
+    pub fn lane_bits(self) -> u64 {
+        match self {
             LaneType::BoolType(ref b) => *b as u64,
             LaneType::FloatType(ref f) => *f as u64,
             LaneType::IntType(ref i) => *i as u64,
         }
     }
 
-    /// Get the name of this lane type.
-    pub fn name(&self) -> String {
-        match *self {
-            LaneType::BoolType(_) => format!("b{}", self.lane_bits()),
-            LaneType::FloatType(_) => format!("f{}", self.lane_bits()),
-            LaneType::IntType(_) => format!("i{}", self.lane_bits()),
-        }
-    }
-
     /// Find the unique number associated with this lane type.
-    pub fn number(&self) -> u8 {
-        LANE_BASE + match *self {
+    pub fn number(self) -> u8 {
+        LANE_BASE + match self {
             LaneType::BoolType(base_types::Bool::B1) => 0,
             LaneType::BoolType(base_types::Bool::B8) => 1,
             LaneType::BoolType(base_types::Bool::B16) => 2,
             LaneType::BoolType(base_types::Bool::B32) => 3,
             LaneType::BoolType(base_types::Bool::B64) => 4,
             LaneType::IntType(base_types::Int::I8) => 5,
             LaneType::IntType(base_types::Int::I16) => 6,
             LaneType::IntType(base_types::Int::I32) => 7,
             LaneType::IntType(base_types::Int::I64) => 8,
             LaneType::FloatType(base_types::Float::F32) => 9,
             LaneType::FloatType(base_types::Float::F64) => 10,
         }
     }
 }
 
+impl fmt::Display for LaneType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LaneType::BoolType(_) => write!(f, "b{}", self.lane_bits()),
+            LaneType::FloatType(_) => write!(f, "f{}", self.lane_bits()),
+            LaneType::IntType(_) => write!(f, "i{}", self.lane_bits()),
+        }
+    }
+}
+
 impl fmt::Debug for LaneType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let inner_msg = format!("bits={}", self.lane_bits());
         write!(
             f,
             "{}",
             match *self {
                 LaneType::BoolType(_) => format!("BoolType({})", inner_msg),
@@ -295,62 +291,63 @@ impl Iterator for LaneTypeIterator {
 /// and a positive number of lanes.
 pub struct VectorType {
     base: LaneType,
     lanes: u64,
 }
 
 impl VectorType {
     /// Initialize a new integer type with `n` bits.
-    pub fn new(base: LaneType, lanes: u64) -> VectorType {
-        VectorType { base, lanes }
+    pub fn new(base: LaneType, lanes: u64) -> Self {
+        Self { base, lanes }
     }
 
     /// Return a string containing the documentation comment for this vector type.
     pub fn doc(&self) -> String {
         format!(
             "A SIMD vector with {} lanes containing a `{}` each.",
             self.lane_count(),
-            self.base.name()
+            self.base
         )
     }
 
     /// Return the number of bits in a lane.
     pub fn lane_bits(&self) -> u64 {
         self.base.lane_bits()
     }
 
     /// Return the number of lanes.
     pub fn lane_count(&self) -> u64 {
         self.lanes
     }
 
-    /// Get the name of this vector type.
-    pub fn name(&self) -> String {
-        format!("{}x{}", self.base.name(), self.lane_count())
-    }
-
     /// Find the unique number associated with this vector type.
     ///
     /// Vector types are encoded with the lane type in the low 4 bits and
     /// log2(lanes) in the high 4 bits, giving a range of 2-256 lanes.
     pub fn number(&self) -> u8 {
         let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
         let base_num = u32::from(self.base.number());
         let num = (lanes_log_2 << 4) + base_num;
         num as u8
     }
 }
 
+impl fmt::Display for VectorType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}x{}", self.base, self.lane_count())
+    }
+}
+
 impl fmt::Debug for VectorType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
             "VectorType(base={}, lanes={})",
-            self.base.name(),
+            self.base,
             self.lane_count()
         )
     }
 }
 
 /// A flat bitvector type. Used for semantics description only.
 pub struct BVType {
     bits: u64,
@@ -366,20 +363,21 @@ impl BVType {
     pub fn doc(&self) -> String {
         format!("A bitvector type with {} bits.", self.bits)
     }
 
     /// Return the number of bits in a lane.
     pub fn lane_bits(&self) -> u64 {
         self.bits
     }
+}
 
-    /// Get the name of this bitvector type.
-    pub fn name(&self) -> String {
-        format!("bv{}", self.bits)
+impl fmt::Display for BVType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "bv{}", self.bits)
     }
 }
 
 impl fmt::Debug for BVType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "BVType(bits={})", self.lane_bits())
     }
 }
@@ -389,60 +387,61 @@ impl fmt::Debug for BVType {
 /// Special types cannot be used to form vectors.
 #[derive(Clone, Copy)]
 pub enum SpecialType {
     Flag(base_types::Flag),
 }
 
 impl SpecialType {
     /// Return a string containing the documentation comment for this special type.
-    pub fn doc(&self) -> String {
-        match *self {
+    pub fn doc(self) -> String {
+        match self {
             SpecialType::Flag(base_types::Flag::IFlags) => String::from(
                 "CPU flags representing the result of an integer comparison. These flags
                 can be tested with an :type:`intcc` condition code.",
             ),
             SpecialType::Flag(base_types::Flag::FFlags) => String::from(
                 "CPU flags representing the result of a floating point comparison. These
                 flags can be tested with a :type:`floatcc` condition code.",
             ),
         }
     }
 
     /// Return the number of bits in a lane.
-    pub fn lane_bits(&self) -> u64 {
-        match *self {
+    pub fn lane_bits(self) -> u64 {
+        match self {
             SpecialType::Flag(_) => 0,
         }
     }
 
-    /// Get the name of this special type.
-    pub fn name(&self) -> String {
-        match *self {
-            SpecialType::Flag(base_types::Flag::IFlags) => "iflags".to_string(),
-            SpecialType::Flag(base_types::Flag::FFlags) => "fflags".to_string(),
+    /// Find the unique number associated with this special type.
+    pub fn number(self) -> u8 {
+        match self {
+            SpecialType::Flag(base_types::Flag::IFlags) => 1,
+            SpecialType::Flag(base_types::Flag::FFlags) => 2,
         }
     }
+}
 
-    /// Find the unique number associated with this special type.
-    pub fn number(&self) -> u8 {
+impl fmt::Display for SpecialType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            SpecialType::Flag(base_types::Flag::IFlags) => 1,
-            SpecialType::Flag(base_types::Flag::FFlags) => 2,
+            SpecialType::Flag(base_types::Flag::IFlags) => write!(f, "iflags"),
+            SpecialType::Flag(base_types::Flag::FFlags) => write!(f, "fflags"),
         }
     }
 }
 
 impl fmt::Debug for SpecialType {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
             "{}",
             match *self {
-                SpecialType::Flag(_) => format!("FlagsType({})", self.name()),
+                SpecialType::Flag(_) => format!("FlagsType({})", self),
             }
         )
     }
 }
 
 impl From<base_types::Flag> for SpecialType {
     fn from(f: base_types::Flag) -> Self {
         SpecialType::Flag(f)
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_registers.rs
@@ -0,0 +1,140 @@
+use cdsl::isa::TargetIsa;
+use cdsl::regs::{RegBank, RegClass};
+use cranelift_entity::EntityRef;
+use error;
+use srcgen::Formatter;
+
+fn gen_regbank(fmt: &mut Formatter, reg_bank: &RegBank) {
+    let names = if reg_bank.names.len() > 0 {
+        format!(r#""{}""#, reg_bank.names.join(r#"", ""#))
+    } else {
+        "".to_string()
+    };
+    fmt.line("RegBank {");
+    fmt.indent(|fmt| {
+        fmt.line(&format!(r#"name: "{}","#, reg_bank.name));
+        fmt.line(&format!("first_unit: {},", reg_bank.first_unit));
+        fmt.line(&format!("units: {},", reg_bank.units));
+        fmt.line(&format!("names: &[{}],", names));
+        fmt.line(&format!(r#"prefix: "{}","#, reg_bank.prefix));
+        fmt.line(&format!("first_toprc: {},", reg_bank.toprcs[0].index()));
+        fmt.line(&format!("num_toprcs: {},", reg_bank.toprcs.len()));
+        fmt.line(&format!(
+            "pressure_tracking: {},",
+            if reg_bank.pressure_tracking {
+                "true"
+            } else {
+                "false"
+            }
+        ));
+    });
+    fmt.line("},");
+}
+
+fn gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter) {
+    let reg_bank = isa.reg_banks.get(reg_class.bank).unwrap();
+
+    let mask: Vec<String> = reg_class
+        .mask(reg_bank.first_unit)
+        .iter()
+        .map(|x| format!("0x{:08x}", x))
+        .collect();
+    let mask = mask.join(", ");
+
+    fmt.line(&format!(
+        "pub static {}_DATA: RegClassData = RegClassData {{",
+        reg_class.name
+    ));
+    fmt.indent(|fmt| {
+        fmt.line(&format!(r#"name: "{}","#, reg_class.name));
+        fmt.line(&format!("index: {},", reg_class.index.index()));
+        fmt.line(&format!("width: {},", reg_class.width));
+        fmt.line(&format!("bank: {},", reg_class.bank.index()));
+        fmt.line(&format!("toprc: {},", reg_class.toprc.index()));
+        fmt.line(&format!(
+            "first: {},",
+            reg_bank.first_unit + reg_class.start
+        ));
+        fmt.line(&format!("subclasses: {:#x},", reg_class.subclass_mask()));
+        fmt.line(&format!("mask: [{}],", mask));
+        fmt.line("info: &INFO,");
+    });
+    fmt.line("};");
+    fmt.line("#[allow(dead_code)]");
+    fmt.line(&format!(
+        "pub static {}: RegClass = &{}_DATA;",
+        reg_class.name, reg_class.name
+    ));
+}
+
+fn gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter) {
+    for unit in 0..reg_bank.units {
+        let v = unit + reg_bank.first_unit;
+        if (unit as usize) < reg_bank.names.len() {
+            fmt.line(&format!("{} = {},", reg_bank.names[unit as usize], v));
+            continue;
+        }
+        fmt.line(&format!("{}{} = {},", reg_bank.prefix, unit, v));
+    }
+}
+
+fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) -> Result<(), error::Error> {
+    // Emit RegInfo.
+    fmt.line("pub static INFO: RegInfo = RegInfo {");
+
+    fmt.indent(|fmt| {
+        fmt.line("banks: &[");
+        // Bank descriptors.
+        fmt.indent(|fmt| {
+            for reg_bank in isa.reg_banks.values() {
+                gen_regbank(fmt, &reg_bank);
+            }
+        });
+        fmt.line("],");
+        // References to register classes.
+        fmt.line("classes: &[");
+        fmt.indent(|fmt| {
+            for reg_class in isa.reg_classes.values() {
+                fmt.line(&format!("&{}_DATA,", reg_class.name));
+            }
+        });
+        fmt.line("],");
+    });
+    fmt.line("};");
+
+    // Register class descriptors.
+    for rc in isa.reg_classes.values() {
+        gen_regclass(&isa, rc, fmt);
+    }
+
+    // Emit constants for all the register units.
+    fmt.line("#[allow(dead_code, non_camel_case_types)]");
+    fmt.line("#[derive(Clone, Copy)]");
+    fmt.line("pub enum RU {");
+    fmt.indent(|fmt| {
+        for reg_bank in isa.reg_banks.values() {
+            gen_regbank_units(reg_bank, fmt);
+        }
+    });
+    fmt.line("}");
+
+    // Emit Into conversion for the RU class.
+    fmt.line("impl Into<RegUnit> for RU {");
+    fmt.indent(|fmt| {
+        fmt.line("fn into(self) -> RegUnit {");
+        fmt.indent(|fmt| {
+            fmt.line("self as RegUnit");
+        });
+        fmt.line("}")
+    });
+    fmt.line("}");
+
+    Ok(())
+}
+
+pub fn generate(isa: TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
+    let mut fmt = Formatter::new();
+    gen_isa(&isa, &mut fmt)?;
+    fmt.update_file(&format!("{}-{}.rs", base_filename, isa.name), out_dir)?;
+    Ok(())
+}
--- a/third_party/rust/cranelift-codegen-meta/src/gen_types.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_types.rs
@@ -8,17 +8,17 @@
 //! type numbering.
 
 use cdsl::types as cdsl_types;
 use error;
 use srcgen;
 
 /// Emit a constant definition of a single value type.
 fn emit_type(ty: &cdsl_types::ValueType, fmt: &mut srcgen::Formatter) -> Result<(), error::Error> {
-    let name = ty.name().to_uppercase();
+    let name = ty.to_string().to_uppercase();
     let number = ty.number().ok_or_else(|| {
         error::Error::with_msg(format!(
             "Could not emit type `{}` which has no number.",
             name
         ))
     })?;
 
     let definition = format!("pub const {}: Type = Type({:#x});\n", name, number);
@@ -42,18 +42,17 @@ fn emit_vectors(bits: u64, fmt: &mut src
     }
 
     Ok(())
 }
 
 /// Emit types using the given formatter object.
 fn emit_types(fmt: &mut srcgen::Formatter) -> Result<(), error::Error> {
     // Emit all of the special types, such as types for CPU flags.
-    for spec in cdsl_types::ValueType::all_special_types().map(|ty| cdsl_types::ValueType::from(ty))
-    {
+    for spec in cdsl_types::ValueType::all_special_types().map(cdsl_types::ValueType::from) {
         emit_type(&spec, fmt)?;
     }
 
     // Emit all of the lane types, such integers, floats, and booleans.
     for ty in cdsl_types::ValueType::all_lane_types().map(cdsl_types::ValueType::from) {
         emit_type(&ty, fmt)?;
     }
 
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm32/mod.rs
@@ -0,0 +1,39 @@
+use cdsl::regs::{RegBankBuilder, RegClassBuilder};
+use isa;
+
+pub fn define() -> isa::TargetIsa {
+    let mut isa = isa::TargetIsa::new("arm32");
+
+    let builder = RegBankBuilder::new("FloatRegs", "s")
+        .units(64)
+        .track_pressure(true);
+    let float_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("IntRegs", "r")
+        .units(16)
+        .track_pressure(true);
+    let int_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FlagRegs", "")
+        .units(1)
+        .names(vec!["nzcv"])
+        .track_pressure(false);
+    let flag_reg = isa.add_reg_bank(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "S", float_regs).count(32);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "D", float_regs).width(2);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "Q", float_regs).width(4);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
+    isa.add_reg_class(builder);
+
+    isa
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/arm64/mod.rs
@@ -0,0 +1,35 @@
+use cdsl::regs::{RegBankBuilder, RegClassBuilder};
+use isa;
+
+pub fn define() -> isa::TargetIsa {
+    let mut isa = isa::TargetIsa::new("arm64");
+
+    // The `x31` regunit serves as the stack pointer / zero register depending on context. We
+    // reserve it and don't model the difference.
+    let builder = RegBankBuilder::new("IntRegs", "x")
+        .units(32)
+        .track_pressure(true);
+    let int_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FloatRegs", "v")
+        .units(32)
+        .track_pressure(true);
+    let float_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FlagRegs", "")
+        .units(1)
+        .names(vec!["nzcv"])
+        .track_pressure(false);
+    let flag_reg = isa.add_reg_bank(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
+    isa.add_reg_class(builder);
+
+    isa
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/mod.rs
@@ -0,0 +1,75 @@
+use cdsl::isa::TargetIsa;
+use std::fmt;
+
+mod arm32;
+mod arm64;
+mod riscv;
+mod x86;
+
+/// Represents known ISA target.
+#[derive(Copy, Clone)]
+pub enum Isa {
+    Riscv,
+    X86,
+    Arm32,
+    Arm64,
+}
+
+impl Isa {
+    /// Creates isa target using name.
+    pub fn new(name: &str) -> Option<Self> {
+        Isa::all()
+            .iter()
+            .cloned()
+            .filter(|isa| isa.to_string() == name)
+            .next()
+    }
+
+    /// Creates isa target from arch.
+    pub fn from_arch(arch: &str) -> Option<Isa> {
+        Isa::all()
+            .iter()
+            .cloned()
+            .filter(|isa| isa.is_arch_applicable(arch))
+            .next()
+    }
+
+    /// Returns all supported isa targets.
+    pub fn all() -> [Isa; 4] {
+        [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
+    }
+
+    /// Checks if arch is applicable for the isa target.
+    fn is_arch_applicable(&self, arch: &str) -> bool {
+        match *self {
+            Isa::Riscv => arch == "riscv",
+            Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
+            Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
+            Isa::Arm64 => arch == "aarch64",
+        }
+    }
+}
+
+impl fmt::Display for Isa {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Isa::Riscv => write!(f, "riscv"),
+            Isa::X86 => write!(f, "x86"),
+            Isa::Arm32 => write!(f, "arm32"),
+            Isa::Arm64 => write!(f, "arm64"),
+        }
+    }
+}
+
+pub fn define_all() -> Vec<TargetIsa> {
+    let isas = vec![
+        riscv::define(),
+        arm32::define(),
+        arm64::define(),
+        x86::define(),
+    ];
+    for isa in isas.iter() {
+        isa.check();
+    }
+    isas
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/riscv/mod.rs
@@ -0,0 +1,24 @@
+use cdsl::regs::{RegBankBuilder, RegClassBuilder};
+use isa;
+
+pub fn define() -> isa::TargetIsa {
+    let mut isa = isa::TargetIsa::new("riscv");
+
+    let builder = RegBankBuilder::new("IntRegs", "x")
+        .units(32)
+        .track_pressure(true);
+    let int_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FloatRegs", "f")
+        .units(32)
+        .track_pressure(true);
+    let float_regs = isa.add_reg_bank(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
+    isa.add_reg_class(builder);
+
+    isa
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/mod.rs
@@ -0,0 +1,43 @@
+use cdsl::regs::{RegBankBuilder, RegClassBuilder};
+use isa;
+
+pub fn define() -> isa::TargetIsa {
+    let mut isa = isa::TargetIsa::new("x86");
+
+    let builder = RegBankBuilder::new("IntRegs", "r")
+        .units(16)
+        .names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"])
+        .track_pressure(true);
+    let int_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FloatRegs", "xmm")
+        .units(16)
+        .track_pressure(true);
+    let float_regs = isa.add_reg_bank(builder);
+
+    let builder = RegBankBuilder::new("FlagRegs", "")
+        .units(1)
+        .names(vec!["rflags"])
+        .track_pressure(false);
+    let flag_reg = isa.add_reg_bank(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
+    let gpr = isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
+    let fpr = isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::subclass_of(&mut isa, "GPR8", gpr, 0, 8);
+    let gpr8 = isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::subclass_of(&mut isa, "ABCD", gpr8, 0, 4);
+    isa.add_reg_class(builder);
+
+    let builder = RegClassBuilder::subclass_of(&mut isa, "FPR8", fpr, 0, 8);
+    isa.add_reg_class(builder);
+
+    isa
+}
--- a/third_party/rust/cranelift-codegen-meta/src/lib.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/lib.rs
@@ -1,6 +1,11 @@
+#[macro_use]
+extern crate cranelift_entity;
+
 pub mod error;
+pub mod gen_registers;
 pub mod gen_types;
+pub mod isa;
 
 mod base;
 mod cdsl;
 mod srcgen;
--- a/third_party/rust/cranelift-codegen-meta/src/srcgen.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/srcgen.rs
@@ -7,75 +7,64 @@ use std::collections::{BTreeMap, HashSet
 use std::fs;
 use std::io::Write;
 use std::path;
 
 use error;
 
 static SHIFTWIDTH: usize = 4;
 
-struct _IndentedScope {
-    fmt: Formatter,
-    after: Option<String>,
-}
-
-impl _IndentedScope {
-    fn _enter(&mut self) {
-        self.fmt._indent_push();
-    }
-
-    fn _exit(&mut self) {
-        self.fmt._indent_pop();
-        if let Some(ref s) = self.after {
-            self.fmt.line(&s);
-        }
-    }
-}
-
 pub struct Formatter {
     indent: usize,
     lines: Vec<String>,
 }
 
 impl Formatter {
     /// Source code formatter class. Used to collect source code to be written
     /// to a file, and keep track of indentation.
-    pub fn new() -> Formatter {
-        Formatter {
+    pub fn new() -> Self {
+        Self {
             indent: 0,
             lines: Vec::new(),
         }
     }
 
     /// Increase current indentation level by one.
-    pub fn _indent_push(&mut self) {
+    pub fn indent_push(&mut self) {
         self.indent += 1;
     }
 
     /// Decrease indentation by one level.
-    pub fn _indent_pop(&mut self) {
+    pub fn indent_pop(&mut self) {
         assert!(self.indent > 0, "Already at top level indentation");
         self.indent -= 1;
     }
 
+    pub fn indent<T, F: FnOnce(&mut Formatter) -> T>(&mut self, f: F) -> T {
+        self.indent_push();
+        let ret = f(self);
+        self.indent_pop();
+        ret
+    }
+
     /// Get the current whitespace indentation in the form of a String.
     fn get_indent(&self) -> String {
         if self.indent == 0 {
             String::new()
         } else {
             format!("{:-1$}", " ", self.indent * SHIFTWIDTH)
         }
     }
 
     /// Get a string containing whitespace outdented one level. Used for
     /// lines of code that are inside a single indented block.
     fn _get_outdent(&mut self) -> String {
-        self._indent_push();
+        self.indent_push();
         let s = self.get_indent();
-        self._indent_pop();
+        self.indent_pop();
         s
     }
 
     /// Add an indented line.
     pub fn line(&mut self, contents: &str) {
         let indented_line = format!("{}{}\n", self.get_indent(), contents);
         self.lines.push(indented_line);
     }
@@ -98,23 +87,16 @@ impl Formatter {
 
         for l in self.lines.iter().map(|l| l.as_bytes()) {
             f.write_all(l)?;
         }
 
         Ok(())
     }
 
-    /// Return a scope object for use with a `with` statement.
-    /// The optional `before` and `after` parameters are surrounding lines
-    /// which are *not* indented.
-    fn _indented(&self, _before: Option<&str>, _after: Option<&str>) -> _IndentedScope {
-        unimplemented!();
-    }
-
     /// Add one or more lines after stripping common indentation.
     pub fn _multi_line(&mut self, s: &str) {
         parse_multiline(s).into_iter().for_each(|l| self.line(&l));
     }
 
     /// Add a comment line.
     pub fn _comment(&mut self, s: &str) {
         let commented_line = format!("// {}", s);
@@ -153,17 +135,16 @@ fn parse_multiline(s: &str) -> Vec<Strin
     let expanded_tab = format!("{:-1$}", " ", SHIFTWIDTH);
     let lines: Vec<String> = s.lines().map(|l| l.replace("\t", &expanded_tab)).collect();
 
     // Determine minimum indentation, ignoring the first line.
     let indent = lines
         .iter()
         .skip(1)
         .map(|l| l.len() - l.trim_left().len())
-        .filter(|&i| i > 0)
         .min();
 
     // Strip off leading blank lines.
     let mut lines_iter = lines.iter().skip_while(|l| l.is_empty());
     let mut trimmed = Vec::with_capacity(lines.len());
 
     // Remove indentation (first line is special)
     if let Some(s) = lines_iter.next().map(|l| l.trim()).map(|l| l.to_string()) {
@@ -252,19 +233,19 @@ mod srcgen_tests {
         let output = parse_multiline(input);
         assert_eq!(output, expected);
     }
 
     #[test]
     fn formatter_basic_example_works() {
         let mut fmt = Formatter::new();
         fmt.line("Hello line 1");
-        fmt._indent_push();
+        fmt.indent_push();
         fmt._comment("Nested comment");
-        fmt._indent_pop();
+        fmt.indent_pop();
         fmt.line("Back home again");
         let expected_lines = vec![
             "Hello line 1\n",
             "    // Nested comment\n",
             "Back home again\n",
         ];
         assert_eq!(fmt.lines, expected_lines);
     }
@@ -272,19 +253,19 @@ mod srcgen_tests {
     #[test]
     fn get_indent_works() {
         let mut fmt = Formatter::new();
         let expected_results = vec!["", "    ", "        ", ""];
 
         let actual_results = Vec::with_capacity(4);
         (0..3).for_each(|_| {
             fmt.get_indent();
-            fmt._indent_push();
+            fmt.indent_push();
         });
-        (0..3).for_each(|_| fmt._indent_pop());
+        (0..3).for_each(|_| fmt.indent_pop());
         fmt.get_indent();
 
         actual_results
             .into_iter()
             .zip(expected_results.into_iter())
             .for_each(|(actual, expected): (String, &str)| assert_eq!(&actual, expected));
     }
 
@@ -295,17 +276,17 @@ mod srcgen_tests {
         let expected_lines = vec!["pub const example: Type = Type(0x0);\n"];
         assert_eq!(fmt.lines, expected_lines);
     }
 
     #[test]
     fn fmt_can_add_indented_line() {
         let mut fmt = Formatter::new();
         fmt.line("hello");
-        fmt._indent_push();
+        fmt.indent_push();
         fmt.line("world");
         let expected_lines = vec!["hello\n", "    world\n"];
         assert_eq!(fmt.lines, expected_lines);
     }
 
     #[test]
     fn fmt_can_add_doc_comments() {
         let mut fmt = Formatter::new();
--- 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":"7d2b91fa0c8cba9be977b41f792fd41646183b455b8736f1c617fa55c7abf454","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"ea5ff1e3ebe7f6f06f9c39c2458268fea3aceb8121d31a3ad311b391631e8408","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"0e146dd56dfb93cac88f9557a3501c9804cff584c2723db27435842bb5e2a1b7","meta-python/base/formats.py":"791e5321fa5030a8a247f3d6e2e395e013e477be3e08059b2ccda66cece96bf9","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"df02d335baf5eba7f1b607b058cf4412cab0c1c81e026cbee923f74146419b77","meta-python/base/legalize.py":"e677e7c97547847731a23fd0fb2a695881beaee6991a7b7a3bb10157c9a17c1c","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"b59efbf787aeae5117eb89f05fc494b6b84e414e7be360613f30adfee6b3d318","meta-python/base/types.py":"98bdfe14ef94090ba8dfbe3e3ca1135e4e2ece4e25d6bac4d15dc72d9a1e5d21","meta-python/build.py":"7aab54a39b555fec3eb9fd771cb2d9467708e3402f8411e88cf11cb32d0c44ca","meta-python/cdsl/__init__.py":"b531693b8228553ca8bd07e1dcd1aa5855f1ad3741b431d758fc27fdd162b024","meta-python/cdsl/ast.py":"552a9a74aa19031ec730912a1e83e405738de9c4df0ddc7fd811b4bd8c2f40fc","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"9ba1b30ed90f2192845e22093179338f2f47e6fe7e15c583cbda2879c006a751","meta-python/cdsl/isa.py":"92bd937c833015f4808f7550f517c4cbc09c6c2e16ecc663d33abb551d124020","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"8663e3b797c7a7313e940456be1d90c3c3cec022aa523b9a9e76fa17e7af51d3","meta-python/cdsl/registers.py":"a8cee541134d34d732926a43f31eb388f684974103d1b1a9645164b0446a3b90","meta-python/cdsl/settings.py":"18dc27dd98a82c814c6aeb2686b40d1fed23661bef5e8b4cbf0fb4e7d39f4755","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"06ac251260a6623d2d58ffbc94529d5faf45a49e5b9c7ec575a84201eb18bece","meta-python/cdsl/test_typevar.py":"714b2d564af1a843629279501436d681cd6590d1988b59e9f50ec940506538bb","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"60019250844ce6b1cdc197f78e02a037223aa65eb18cfb5f17369d84d93d4fe7","meta-python/cdsl/types.py":"d332fe96c0be47d33f651b6cb6339a8c91e7e170832ec2f27b8a5b02bd549a6a","meta-python/cdsl/typevar.py":"a1a405149343011255ff69edb44cf5f960559d1351b6ec07cf6d0bd668d87c4b","meta-python/cdsl/xform.py":"b9db7dd9a4b32e2cfc34def1d2e3213f1fb250a0f66b3aca2c1f30129437d4b6","meta-python/check.sh":"9e2f70f2d762c840f1d49519b024b4c1b93168137184b5e3e605e55813c62ea5","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"3920c5c89451c26102f7d87c61de64c94e915a545bc8a35d2e49106aecf019ec","meta-python/gen_encoding.py":"73a216007ec6e90acf74f51657516de0465fbb692d08c9db0885b1c2aec502a9","meta-python/gen_instr.py":"e9f71675ebc82ee6151c1d671449418939f1e258a504f9b16bebe799788771df","meta-python/gen_legalizer.py":"187a47f1702e07487fb8a13076aadcf9c2de3e801d367424dc847ff7b0ed70f1","meta-python/gen_registers.py":"cfde66d3d75ac7e647afa5a0a7051f5fc1ac757cf142b497f549e57ceb6ff54b","meta-python/gen_settings.py":"44c231ab8d2aa4f18cbe4fb5a33fb72103503d58f5af22c7b545eeffbf97da79","meta-python/gen_types.py":"0cff50db1ecebc2ba67d7e02ed6ab975713d460083cb03ee8a9bc58d021e3ca2","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"bfc32c901e3e5f46cb6d50167736b967862d2e4f54535986ce20b38f933e4588","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"b964bd028aedc5422e1ef3a088f456dac4feb10e6d310858cee9245479fa3547","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"f92e8b3007198bb85139172d2d19fb5b3462d92012282e1877b05e1c07673332","meta-python/isa/x86/registers.py":"60a9f42fede6330cd7ef001d85ece9f7095cbc20fc4004de65a3dd9972236293","meta-python/isa/x86/settings.py":"d779a768475cf00c2a8d3ddb5cd0a70ce34662e0ebb52ee26a7e1a495ec41aa2","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"3df36e0a986fd90d0b69740b02671251ecd2853873998dcb6d379894a4f9460b","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"825edfbb9221bf59c02fea26e55d17cf32194da7a9f56ed0e035c44353481055","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_gen_legalizer.py":"f16edce7cb2ce53e55b1fc56b6f5ba6a0fc61b291ee4513ec859e36d69f0e285","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"29f505fdfcb6ec14e561bb408b99ab30ab69b96d1e283a1dcd55db9aff02dbe4","src/binemit/memorysink.rs":"85adb793c5eb5711aca64534225eb4fc98ae0c79cea42dd6d86e9c193dec97cc","src/binemit/mod.rs":"95ed53492873dfbed44cd185085740ab20f9e7543a26855f0466e7a607f6ff54","src/binemit/relaxation.rs":"dd8b50f32ba9688c7f6d0e2957c120192e3d26d8301db405038ab1ece4777746","src/binemit/shrink.rs":"6b5622701f4496c6fc540555236716749f053e126102f73e63b03f3306e50670","src/bitset.rs":"67fd02dd2acb9af73e45426e5cab1d2a74d568a11d11ee17ae6a4421f96cf741","src/cfg_printer.rs":"1bbe85c44002222c38a54f1c741f99e4ba6eb1e90e377907e62504ede847ef93","src/constant_hash.rs":"493cdf8f607eab01bb52f93d616fb6190c7c86d3a02e530b0ced30993d4bfda0","src/context.rs":"29222884fd459d3d056ab1f490165a7bb8b9d27fe1ed297fd8f06a6ad7c9f46f","src/cursor.rs":"7dd7cc957c0d1ad0850162b6a0d3f13b8f0d8cc00e22d481458df7b2486611a7","src/dbg.rs":"bae915e1f7544f725817b368aed00a6aaa9e394a454dc847d65ad44e54d78cb9","src/dce.rs":"6d015824ae0325f01bb523606d7e15dd5feeb72a75b947f40385feeba94555c8","src/divconst_magic_numbers.rs":"eac50e2353e17ab6f7d1da3bd8e0e8dc9e3122a160efba594d407eb6a8936cc7","src/dominator_tree.rs":"595031c03afa61020b26eb071a26d6c4949361f5e4e0e8b516e5a04adf200fe3","src/flowgraph.rs":"337341ed7d9070e46fc0048f1069a95c985ffe4b405f9a10e606a38b5e05851f","src/fx.rs":"2fb53f141b3e6be1882a1e4afac4bc607ce694f045d9329ee823e0aca415898e","src/ir/builder.rs":"740fead2c1986e5f3a836de06b37e6a45188a7d40c64f86c5097624e92c6e9d6","src/ir/condcodes.rs":"5456a25798516245b0923c9e12ae0af5cc98c097fc6f3bc0bf2d7af5008667f7","src/ir/dfg.rs":"0e61ea5a0515a73ae57d7625b0a67d82d6f8b5c0ba6673d1eae0d3b48745edbc","src/ir/entities.rs":"1505347c2baa256b04f69384d1391f52e007d533cb4319d3826cf3046ec1df27","src/ir/extfunc.rs":"69a838ddeb29fec19c6b308540259b971eb85be0fbab84647d68bd36d1f79c3d","src/ir/extname.rs":"839e3d694e5c109bb594fe31c7d9dfe4f156bbc2eb695f3412fd39c325374b91","src/ir/function.rs":"05808190e4764acdda07dd2f5750853310f06aa8848e3612dfce074f17837261","src/ir/globalvalue.rs":"8c9bc996332f6c7cb549a1d1296ed9f5783d364c1a5c9b5250745d412729f2be","src/ir/heap.rs":"dc9d4f0eade20d58b3e2678c329452fbd5965c46d6121cbf5889f2588ae88772","src/ir/immediates.rs":"0f1806af474a6bef2a4a488fae7b42482c6b05b4cf658069c6881b48b6b68ab0","src/ir/instructions.rs":"40a41505497fc03d2e0f25b3739378252a94566383b446016fa3be0879ddc1c8","src/ir/jumptable.rs":"7dae4bbc9538d05a6fc969800146327eb96b7d75aff976807edece5c6166537c","src/ir/layout.rs":"daf934675b0cfc227080538cfa2329b519f748dcc9e21539ba903670801b86a1","src/ir/libcall.rs":"c4405665b00fc199c520e6b5d637189736307e69793db6ada67242feecabc852","src/ir/memflags.rs":"988a07cf60facaee75c867b093332e311664ecfe405e2cf29ef5c59376f2ef61","src/ir/mod.rs":"2ac265cd091915aee161dd34c34f3b17d3590412bc41c09c763fa2d92a6bb626","src/ir/progpoint.rs":"d5191447f82bb612ae25ebceb5ecc2099a902be5aaecd5b9d418dcbd8a2747a5","src/ir/sourceloc.rs":"79eb71609b844839994fc735cd72edf53179eb659303a4150634928e207cee4f","src/ir/stackslot.rs":"669fb7b1692012d7c51fa53c3a1e49774045fc68d9c4a47995aeb7fb3e0027d4","src/ir/table.rs":"810e92631257e1e54577563df1da9709134438d0eab3db5e540500e69437a16b","src/ir/trapcode.rs":"233d73e4a2abbfc767aac7868d4adbb24cedaf8e7e42a640d590bda2e776784a","src/ir/types.rs":"50c3b48a60be236b37342063ee473ec4115d6d965a12673ac1588b050025f030","src/ir/valueloc.rs":"5055897d9acba6d9c396b126889f9b2c7ff3f54a27c1ec5fe70d1a059d633b36","src/isa/arm32/abi.rs":"50ca3161a0f11ba1c2d5b0ff7523d332503cb6a6182695246e4284a486e18cab","src/isa/arm32/binemit.rs":"3197df7b15c223f3a9f2708311375ff423bb247381cf21e26da079f7933f5279","src/isa/arm32/enc_tables.rs":"dacb50bdacfa2085a6283818563e19874590d223e5decb5c91b968e0348e2bf7","src/isa/arm32/mod.rs":"da68e5ad27697b75ef34440cea045d077d8050026b6f279e40536c44be64a1b3","src/isa/arm32/registers.rs":"0e5c32a218d685c6d37fb46788baedf6bede6be7d4f715808c13620636dfc472","src/isa/arm32/settings.rs":"145f59227c6087e7872f66a6d2183c66e061c40466e7b427a733136e41e41207","src/isa/arm64/abi.rs":"bfd0065a6c26eb407872959c9d7f64169591afa4d69816370e0900aa1ad4e46f","src/isa/arm64/binemit.rs":"159ab9eca03ac4aa7f55d51ab20585a5971d95a74c61953d1899ac863b06e2ec","src/isa/arm64/enc_tables.rs":"00ec8f53402f6cb73716db1adb3aca564574833cab58dc12b4dc6ba8c4529a73","src/isa/arm64/mod.rs":"be67ce9475a2b2fdeee12ff4eae76fe3d2a6919807f1d015b501e16135e82471","src/isa/arm64/registers.rs":"7a8b207ed28737efc737e8e65ce79e7e7d3eecd23599890230dca8474c985026","src/isa/arm64/settings.rs":"7b466fcc2c58bc1846a72f08ec58900b3cf622ab2922ee9128e6dfe254907bf5","src/isa/constraints.rs":"324d7c8655565f13b90a6c9587c9fb6c545ab3086201f434e1324fc5d6e5b3c7","src/isa/enc_tables.rs":"b6cf1a2e58a34170360681f517d89bb7aac1ed7586792e3d36156ca7326abcc5","src/isa/encoding.rs":"c8746f8c432a02e092dae80a9342734da760ad055854d598ffb395a47ed9d884","src/isa/mod.rs":"f86fad997fd136a3c44c70d3d7ca221a6bce64e8c1e69bea32fe1554bca9642b","src/isa/registers.rs":"9116fa8eb488b5d1e96f6718825cc4220a3f283ba629548a44267167c9683df8","src/isa/riscv/abi.rs":"1de6d0070126e0127ca6a63551a14d1b5c030cf9628538fd732301fd2bd34b5e","src/isa/riscv/binemit.rs":"3bdad2791447f51bfe5ecedb73b1aed8a6a8809790b1f26e3ff624a89163a026","src/isa/riscv/enc_tables.rs":"9c0303ef10098dc0a99021cddc3432e222874bff1d4b8f8ddc7daa05c6b77ddb","src/isa/riscv/mod.rs":"9a7a6ca8ba9273f772b3b7507072ec46975d067f572f71d86067bb8ed854b077","src/isa/riscv/registers.rs":"794ac61343a8db66dc99b2ca964ea3986b47b37fe8b72575c644c1cdaabd2991","src/isa/riscv/settings.rs":"78ced69b82d89f83b5612a91d0acdac2616f9091b380ee3e4715adb31f95b232","src/isa/stack.rs":"ec96130c446cd7d637722f1603e38d5164498368b652f4b0454baf3227385ad4","src/isa/x86/abi.rs":"bccfac45421a01002aae42acf8a14fdbc17e44299f08e10abaf0507578e744e3","src/isa/x86/binemit.rs":"48df284ed2cff76cea1e94cd08a6badd513787123ddf4984c495d745d6e59756","src/isa/x86/enc_tables.rs":"ac913a8fc45b1d5a863ce3dd760692e32ccb5f4f47fadd6b9f26f9df51b963d2","src/isa/x86/mod.rs":"146d059936b85ceb4983b3bcc9b875b7eaccbc5c1a9d34c435b8c4f7a737d87d","src/isa/x86/registers.rs":"783ebbe4c3b4711fe1eac2cfd3bbea7c31a53c15c6028397c038ef4eb0b2aa06","src/isa/x86/settings.rs":"dcce098045c1115cd55f256dcd3e0ccaa5a0c9ad93b14fb8a4c680e95caf2b73","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"d070da577a4a11a3bed9adbfdf94bec8aff368b4d176b1b85a44739545561a1c","src/legalizer/call.rs":"12f380d126765f0bc2da1cf298088fa98451e2d6bf56c34b755ff7077d14a4f1","src/legalizer/globalvalue.rs":"eb5d19a653928e2da0b78e38555b1d41f9549eeeca9fb6295a7dc5197ebd3c3f","src/legalizer/heap.rs":"c44a0845254187dfe7456b0b9efbfea25ae566772bc64b41ed93dd32a71f8e8a","src/legalizer/libcall.rs":"bf18267f502bf9bfbc3ff51bc05df480293a84422ea7f4c37dd0c75e97952766","src/legalizer/mod.rs":"c3707143cdd2b215b15ce7c0fa95d0df36a2cbf2e13dbe08d7166afa2e416f7a","src/legalizer/split.rs":"ae07854aad2ff2aa83a6ba08276b49a462dda0591faa9a61bdc7ca787451078f","src/legalizer/table.rs":"2aca27ea564c2ef02ed833c495156b9e1ddcee3c8a1b1e70347ab5907a381605","src/lib.rs":"95e48756b120856a91094e76c0acfc34abe86d93fe0bb9771063e7aec1af8315","src/licm.rs":"9657ccfdcf7a52eca1ba201d455f1d538f17aaa6295b9651282de9f7c79a53b9","src/loop_analysis.rs":"9b622be0af7a36f9ed2fb91bd4b6905785b63e0fc88d5765dd5f18a06f2f7834","src/nan_canonicalization.rs":"e2b1f9935d14af9abe553de1eda5483cffdaa7098dd1a17ba9a98fa04280b22c","src/partition_slice.rs":"55b9e857f452baf4d6312779861f9ef93b3d5300467e752230ec6af14943efe3","src/postopt.rs":"6a182d8646d6964c7137320bcd4b3c5cada62cac31a34e41050d3d6eeeaa9a98","src/predicates.rs":"fdb15850c86b9b45a13a1e791ef51ce843460b20e360d44dbdfdf198f59dc40d","src/preopt.rs":"cfafd0398bba0b3e2b91b5bf10617bd4048ba2b22345b3e5bfc403239903960a","src/print_errors.rs":"89b9f516c0567bada88e8fa9aea7d8e9f5acadbaea3ae5cb8215619433f1e5ee","src/ref_slice.rs":"9be914b705eefcc6b4e38db573f56ad7b978f4b65c2f6f8f5516df78fb2206a4","src/regalloc/affinity.rs":"47e28f9ae7cebfc9b1006480143a3a5ab1b118ec761a163c4a670b63fdc47d0a","src/regalloc/coalescing.rs":"253e3fb916c37453f0fa4f963caf5336712d60447e39f63a6696c2ad22cb102f","src/regalloc/coloring.rs":"fdcb1bda766220a7be0f815d8431e317dfc007a409c2c095948b45032a98c3e7","src/regalloc/context.rs":"794f9f0fb3b980feb3be57b95c152767cb318b81aca48c27197b01b7d529c48d","src/regalloc/diversion.rs":"cbb942a197081f9e537f3fed71a7ec6d6d1edc18b8536fa46a1dda316f46c776","src/regalloc/live_value_tracker.rs":"054efd9e8da0f33a158082f67a7c2c14f7c8632b1fc28d54941ca7bc9d5a46d6","src/regalloc/liveness.rs":"b21e4855c0339c1b15b1b62e63bb1a569c4256b42d08c3c21b6e7fc4634c5e62","src/regalloc/liverange.rs":"c7395c8c3709996f8d17a196af541ddbb37a9a20b1c3c151dd10628000ece337","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"7c73ca1f54559b1d9f8ce587bdc067e74f3d47901058f7ae1e9277516624236f","src/regalloc/register_set.rs":"e1554d01a3a5a13acc4e0092681eb3fc090d9c68eb71f8a9985c01c7a3f2e3e2","src/regalloc/reload.rs":"cab64c91c57831d17e7e5ec217639f127b7608aedbfcb3c25cf3b9dfae36812d","src/regalloc/solver.rs":"853c6f16f68e75add56981b132d92e556a94d8cbd13fed311df2d75da08de03a","src/regalloc/spilling.rs":"eb7c625395c790ada187c0938dbcca6d43426a7f6d4a9ef0317778790a9dc38f","src/regalloc/virtregs.rs":"fb06b52b9b8ab0e139cb03105785ca94057c08c9277423317fb4c0040844ddde","src/result.rs":"d43abf9b22c5ad772200889bba339bcc4455c7abb9f2f3a2af65fbbaf1130009","src/scoped_hash_map.rs":"102797c380a588f7c16d26bf3b6c9cff28d37c2d8168a382b265194cd8969212","src/settings.rs":"2b0ddf77a4e18cf15292673502150b6b0af4d22ba03be9d1aadb654b6c1f91e1","src/simple_gvn.rs":"4d765fe40c527cbcac287a59d513dcc7b983d060893017579ec2b4f57b1411fc","src/stack_layout.rs":"ce0b4b188cc46fa5070139124ffb2d263d44acd08703e7043a40b5c1afa952fb","src/timing.rs":"d974dc0498ee814e90c5ecaaf60949f1b8d97213c4676114ed3d88affac56a02","src/topo_order.rs":"4ea901ec69bc1112ae496f26fea7de1f48cb2f1c1726525b367496fd3b4b3f23","src/unreachable_code.rs":"6fdea8f9afe9fbffe411bfef48fec7937cb41d51036fd190a3d0a5f0cc2894c6","src/verifier/cssa.rs":"8f41765d18474575faa7c44a0345549dabe0af07141e2f004a7db1c67486ce77","src/verifier/flags.rs":"80ecfdac53899ab4f35e8ba3f948b8cb32768184608bc0864029cf6d953d6c5c","src/verifier/liveness.rs":"6e827f05461bd6fb21b0ce99f02fae374f2d6ea6e7e14ba61e88983a1c6fac4b","src/verifier/locations.rs":"c3fbc688e021f5dabf20ea435cfa09da5e757229de6d9ef0465522898f44d0bd","src/verifier/mod.rs":"8fa2e17ef36a0a265b617a696edca33dc9fc5bcce5aace1519214f58d102bc60","src/write.rs":"f3bec214b6f6ef8f1ce11e056a5b14365d2adc122bbf725127b6ebb04c8dcc5b"},"package":"16f418f1d1e6221812a7d35cff5b9a572dc978c002e33792134bbd50c07cacca"}
\ No newline at end of file
+{"files":{"Cargo.toml":"0b0ed9a5aee750b88bed0d2a120fc9ca0a8dcf3a92a03582f08e7287ce3fbb4a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"513cfea9d05e69a1f3b596f91f40dd380ab0368931e5dc869dbd3959192b6792","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"0e146dd56dfb93cac88f9557a3501c9804cff584c2723db27435842bb5e2a1b7","meta-python/base/formats.py":"f9fb41210bc1f99a78cb7a60ee9f01c603412c6b1db7e69abbcc0f573cf9fb40","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"4c3f8ee6c29e8cc9e19172f707890d613ed4173bda9b9de7857dae2b28babcbd","meta-python/base/legalize.py":"57b71ec3599fbf998c1926e4b48566661b7feec01dbd8bd177d0d2aaa26a44c2","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"97fca9ddaab347f50f1594c93283f8f474e53a7232eae65949f56a6a702c2bba","meta-python/base/types.py":"9616d6fe4cab050827ab02eeb9843eacebbb8f7555521f504b5ee2ddf7214fdb","meta-python/build.py":"b72a80a54e09366878e92dca3a1508af394bf71a0c4b07a05e54058901373d34","meta-python/cdsl/__init__.py":"b531693b8228553ca8bd07e1dcd1aa5855f1ad3741b431d758fc27fdd162b024","meta-python/cdsl/ast.py":"b7c09f69b28b5754f494912ca5b77722dbd4ee416d5fad79cb48322eb544ea9f","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"b0ddfd8fd22889bd1e610c103d47087c9c6ae5882862ed44921dafc2ae0463a0","meta-python/cdsl/isa.py":"96e31674d699cfc846f65ee2ab62a199215e7ce012c6d43ea36ea5d2f839402e","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"def3f91712744671df9cf3d4f9c255a2061f341198689e31addf7db4efb63e36","meta-python/cdsl/registers.py":"939dafd1b8976a6cd456c9a5e4b374af81fafb9da979ea3a1f6d14e4645914a6","meta-python/cdsl/settings.py":"18dc27dd98a82c814c6aeb2686b40d1fed23661bef5e8b4cbf0fb4e7d39f4755","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"57966c9eb027fa73bbc7ad81094ff55232053fbb2e16d78849ae3b6e9b1c2989","meta-python/cdsl/test_typevar.py":"714b2d564af1a843629279501436d681cd6590d1988b59e9f50ec940506538bb","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"a1a7ff79f8a2196aee491a3aafbd4f1b231004bbb5281992fc8f4e43f4fb951f","meta-python/cdsl/types.py":"adee4bbc1a9478288fa4b53ee1edeb5ee3296dba2c70bfbe01e923895064999e","meta-python/cdsl/typevar.py":"b5669934eddaf5b9cc0c27b966e2566b5f669f1c5a345f005960930fb499097e","meta-python/cdsl/xform.py":"5cdad80f12d50aa9491cd3d39797e6c0444936bb0874199d7c34e6d735658b34","meta-python/check.sh":"9e2f70f2d762c840f1d49519b024b4c1b93168137184b5e3e605e55813c62ea5","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"3920c5c89451c26102f7d87c61de64c94e915a545bc8a35d2e49106aecf019ec","meta-python/gen_encoding.py":"0b57d9d74a72a1b3b11721166fdbaa8b8c4b2d7493fc10b88736ac330b83256f","meta-python/gen_instr.py":"7ccd6a6bb1ce1800ea9c2c37e462ac7ded4f908e311d708080f7d21d92578316","meta-python/gen_legalizer.py":"187a47f1702e07487fb8a13076aadcf9c2de3e801d367424dc847ff7b0ed70f1","meta-python/gen_settings.py":"44c231ab8d2aa4f18cbe4fb5a33fb72103503d58f5af22c7b545eeffbf97da79","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"3852e5b7aa6995fa721ba91744a0470343ce1834651e7b9cc97b5d69af7dfdc5","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"dc758c5bf95b9271e70203c481df0dc9b3363c4f730cfc564e4e3f5f275a6433","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"edc60f964816026e27136cb284eec28220f088b472a54e1bd90b3e8ccfe0648d","meta-python/isa/x86/registers.py":"ff934491d07ec6b51fbfd454b865a7c7c191ffbd31b1804615735266b120f4b2","meta-python/isa/x86/settings.py":"d779a768475cf00c2a8d3ddb5cd0a70ce34662e0ebb52ee26a7e1a495ec41aa2","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"e8a25a111f2d9cc9fc7aa498a572a86403d31fe50a7ba59dd2e2560a17804e92","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"825edfbb9221bf59c02fea26e55d17cf32194da7a9f56ed0e035c44353481055","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_gen_legalizer.py":"f16edce7cb2ce53e55b1fc56b6f5ba6a0fc61b291ee4513ec859e36d69f0e285","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"29f505fdfcb6ec14e561bb408b99ab30ab69b96d1e283a1dcd55db9aff02dbe4","src/binemit/memorysink.rs":"8437e5f5c1b3e68b8e2d0de6fb3a4982f7a06390a0f8820b6379492408df8964","src/binemit/mod.rs":"2f95ea5f6ee20b8d56bdedcacdd41a609c5b999c02affca341d6a71eb59bc113","src/binemit/relaxation.rs":"5facfa8e15a26cba42210102a6fd735df1ba291adf512dabc85c0951239291f8","src/binemit/shrink.rs":"428679a02e44a7b3621a43c7d2e8d2f3b2cb50a36179a4d9862205c0ba34ae50","src/bitset.rs":"67fd02dd2acb9af73e45426e5cab1d2a74d568a11d11ee17ae6a4421f96cf741","src/cfg_printer.rs":"8c0fda88060c204985a6406ba46d7f0a69be96bb18c9fcfc70055d50986068ab","src/constant_hash.rs":"493cdf8f607eab01bb52f93d616fb6190c7c86d3a02e530b0ced30993d4bfda0","src/context.rs":"bfb491dc9c99c05cb906caec4a198a962ae4733ac32eda8f4aad127735511488","src/cursor.rs":"523899307d471f63e9ca35ee4b3340cf55041561a05b199e11cc60f6ad2714f4","src/dbg.rs":"bae915e1f7544f725817b368aed00a6aaa9e394a454dc847d65ad44e54d78cb9","src/dce.rs":"6d015824ae0325f01bb523606d7e15dd5feeb72a75b947f40385feeba94555c8","src/divconst_magic_numbers.rs":"eac50e2353e17ab6f7d1da3bd8e0e8dc9e3122a160efba594d407eb6a8936cc7","src/dominator_tree.rs":"73032e0e7a0ab694aa3181222bccb40630bd6fbda33885a391fd662f7de7d540","src/flowgraph.rs":"fccfade2b24038e18d469e273976f418757159fde140642b5faeb3c664a756ce","src/fx.rs":"2fb53f141b3e6be1882a1e4afac4bc607ce694f045d9329ee823e0aca415898e","src/ir/builder.rs":"19aa7cef76b7577bdd9d769fb1260080a959f9bfdbac569fb1e38307a721a03c","src/ir/condcodes.rs":"5456a25798516245b0923c9e12ae0af5cc98c097fc6f3bc0bf2d7af5008667f7","src/ir/dfg.rs":"bc975909538056b9f1dc1dacf4f6078d93f2983ad7de1c8fba3c4bee028dcc85","src/ir/entities.rs":"1505347c2baa256b04f69384d1391f52e007d533cb4319d3826cf3046ec1df27","src/ir/extfunc.rs":"9a3535730a39a6b71ca9f1ed679f588e6c3fa48ee7a50489d90803f3134db4a6","src/ir/extname.rs":"839e3d694e5c109bb594fe31c7d9dfe4f156bbc2eb695f3412fd39c325374b91","src/ir/function.rs":"55feb0b0a2bf4a0d194a4d11fc297616c78d5edfa41504795742fd25e7af1399","src/ir/globalvalue.rs":"bf9b76430f6ba564d4e5db85dbebfddf952678be6914326a5549b569c064d03d","src/ir/heap.rs":"dc9d4f0eade20d58b3e2678c329452fbd5965c46d6121cbf5889f2588ae88772","src/ir/immediates.rs":"5f57bc2a46b7ca11e1e495e657cedbf493194025eceb6591ba8792aff6910f88","src/ir/instructions.rs":"be6493d0a507f1a9a9ec37a3bb976998ee8e1355c44ae7c656c82a6edacfbec7","src/ir/jumptable.rs":"3fc108096e5404c4c30220cfaa4e359caa83bad747268bea88bbc0ac4b1bcd13","src/ir/layout.rs":"77210d256e39d339736ced5518c8d666da6359f656b972d6b6b19581ccaec329","src/ir/libcall.rs":"b35c8d0c90e686a176f9bd157ef6ab3819e8a0b974d0d24007a910ffb0d15f51","src/ir/memflags.rs":"5819e1171c620f171020bf26df9513eb6bee9890da8a7ebabbd1506b1d123f91","src/ir/mod.rs":"16566fb92fc16498d5a2699fa76dfdbc39665a4e8bae3040c03e4f3d2f07e3cb","src/ir/progpoint.rs":"d5191447f82bb612ae25ebceb5ecc2099a902be5aaecd5b9d418dcbd8a2747a5","src/ir/sourceloc.rs":"79eb71609b844839994fc735cd72edf53179eb659303a4150634928e207cee4f","src/ir/stackslot.rs":"d5d0c61555bf7060c58603047356b7db53b5b296497daed8eac356b9e724902d","src/ir/table.rs":"810e92631257e1e54577563df1da9709134438d0eab3db5e540500e69437a16b","src/ir/trapcode.rs":"233d73e4a2abbfc767aac7868d4adbb24cedaf8e7e42a640d590bda2e776784a","src/ir/types.rs":"1f93f886dba75f6bc267b35e2fc6ed1564074a8885af13d6c85c28574acf8436","src/ir/valueloc.rs":"5055897d9acba6d9c396b126889f9b2c7ff3f54a27c1ec5fe70d1a059d633b36","src/isa/arm32/abi.rs":"50ca3161a0f11ba1c2d5b0ff7523d332503cb6a6182695246e4284a486e18cab","src/isa/arm32/binemit.rs":"3197df7b15c223f3a9f2708311375ff423bb247381cf21e26da079f7933f5279","src/isa/arm32/enc_tables.rs":"dacb50bdacfa2085a6283818563e19874590d223e5decb5c91b968e0348e2bf7","src/isa/arm32/mod.rs":"798049325ca439444a5508f63ebb53bf2e0ab16b128c43417017bbdb2fd95742","src/isa/arm32/registers.rs":"0e5c32a218d685c6d37fb46788baedf6bede6be7d4f715808c13620636dfc472","src/isa/arm32/settings.rs":"145f59227c6087e7872f66a6d2183c66e061c40466e7b427a733136e41e41207","src/isa/arm64/abi.rs":"bfd0065a6c26eb407872959c9d7f64169591afa4d69816370e0900aa1ad4e46f","src/isa/arm64/binemit.rs":"159ab9eca03ac4aa7f55d51ab20585a5971d95a74c61953d1899ac863b06e2ec","src/isa/arm64/enc_tables.rs":"00ec8f53402f6cb73716db1adb3aca564574833cab58dc12b4dc6ba8c4529a73","src/isa/arm64/mod.rs":"4eef5f904f2219262c59dae7056af5adb7764074309dffc0be5b2357781dd1a6","src/isa/arm64/registers.rs":"7a8b207ed28737efc737e8e65ce79e7e7d3eecd23599890230dca8474c985026","src/isa/arm64/settings.rs":"7b466fcc2c58bc1846a72f08ec58900b3cf622ab2922ee9128e6dfe254907bf5","src/isa/call_conv.rs":"4bc8f8cc540ed54cf1e4c4688a1a8a975ed49a039a48d44a2c6b97f847b65ea8","src/isa/constraints.rs":"324d7c8655565f13b90a6c9587c9fb6c545ab3086201f434e1324fc5d6e5b3c7","src/isa/enc_tables.rs":"c8e9b1293917d061fcb26899cc21bd6f6c99f29ef5d1da8e2c537f343cf4ec64","src/isa/encoding.rs":"032347d4e624449af7a35f7ba012339bc49fabae97b971818e922d6ca4510e59","src/isa/mod.rs":"e3cbdf52862ac052292965dc399d832e9684a42099df5d5fd06f5fcdf5781cba","src/isa/registers.rs":"c0014dc940e8a6da628c60e49f6261cebaee1e06e0ea1c172de5f797e600535c","src/isa/riscv/abi.rs":"1de6d0070126e0127ca6a63551a14d1b5c030cf9628538fd732301fd2bd34b5e","src/isa/riscv/binemit.rs":"3bdad2791447f51bfe5ecedb73b1aed8a6a8809790b1f26e3ff624a89163a026","src/isa/riscv/enc_tables.rs":"6bc179f95ef5634b64fb42ab67929c0aeb70ac8efccfc47dd8c9b1dbfe64a446","src/isa/riscv/mod.rs":"de0dd32005f6b0510e3c8a31bb7e58ab7e7cffb674169a08558794950db87126","src/isa/riscv/registers.rs":"794ac61343a8db66dc99b2ca964ea3986b47b37fe8b72575c644c1cdaabd2991","src/isa/riscv/settings.rs":"78ced69b82d89f83b5612a91d0acdac2616f9091b380ee3e4715adb31f95b232","src/isa/stack.rs":"ec96130c446cd7d637722f1603e38d5164498368b652f4b0454baf3227385ad4","src/isa/x86/abi.rs":"82d592bfae4810813f7d1328e172376f7679f077834c0150d776d0d08842d089","src/isa/x86/binemit.rs":"f90820a1f9c4ad02f3507625d35f014f644d8cea93b0216bcc60cc05cc84eacc","src/isa/x86/enc_tables.rs":"06c625ceef65e395d8134597b20496f3ea0874e13ecf84fa2ff2a8e9e623b2b6","src/isa/x86/mod.rs":"bc83c0e619e8603885359c472b4113bc83b8867dd2d8e83b27f798301c6df93c","src/isa/x86/registers.rs":"783ebbe4c3b4711fe1eac2cfd3bbea7c31a53c15c6028397c038ef4eb0b2aa06","src/isa/x86/settings.rs":"dcce098045c1115cd55f256dcd3e0ccaa5a0c9ad93b14fb8a4c680e95caf2b73","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"ff36220e78d9639046b1c9741c93f5333aa412256949b8842b6c31f97a6e441b","src/legalizer/call.rs":"12f380d126765f0bc2da1cf298088fa98451e2d6bf56c34b755ff7077d14a4f1","src/legalizer/globalvalue.rs":"be6fc6e310dedde48e172453eccaa7cb416baa92e1adfc55f565d51159c930cc","src/legalizer/heap.rs":"c44a0845254187dfe7456b0b9efbfea25ae566772bc64b41ed93dd32a71f8e8a","src/legalizer/libcall.rs":"bf18267f502bf9bfbc3ff51bc05df480293a84422ea7f4c37dd0c75e97952766","src/legalizer/mod.rs":"f516c4e22fb66099678f753121dfa92128f2c4524ea4196e1b400e06e6649d44","src/legalizer/split.rs":"ae07854aad2ff2aa83a6ba08276b49a462dda0591faa9a61bdc7ca787451078f","src/legalizer/table.rs":"2aca27ea564c2ef02ed833c495156b9e1ddcee3c8a1b1e70347ab5907a381605","src/lib.rs":"1542f5cae0d80c408f190d225890da959e0b4033687b6c2480e83254341cba83","src/licm.rs":"9657ccfdcf7a52eca1ba201d455f1d538f17aaa6295b9651282de9f7c79a53b9","src/loop_analysis.rs":"ab74f702649ddd16d3d91400c3c2aafed4f09d9af210f5e180dff15a82caf8ac","src/nan_canonicalization.rs":"e2b1f9935d14af9abe553de1eda5483cffdaa7098dd1a17ba9a98fa04280b22c","src/partition_slice.rs":"55b9e857f452baf4d6312779861f9ef93b3d5300467e752230ec6af14943efe3","src/postopt.rs":"f1fe06398c644cad19fd427323c74acdb237b5853ffb72148a2b2012b906e2a3","src/predicates.rs":"8e4c4afde65420d33621aedd80e4ce270d334c1b62a17d7879273a1719d49b41","src/print_errors.rs":"60f9ba4ca69a0c307915d9e7290dbf15c6622e688a3c02911b67f9e8568b4111","src/ref_slice.rs":"9be914b705eefcc6b4e38db573f56ad7b978f4b65c2f6f8f5516df78fb2206a4","src/regalloc/affinity.rs":"47e28f9ae7cebfc9b1006480143a3a5ab1b118ec761a163c4a670b63fdc47d0a","src/regalloc/coalescing.rs":"253e3fb916c37453f0fa4f963caf5336712d60447e39f63a6696c2ad22cb102f","src/regalloc/coloring.rs":"baf4861cabfc897755bef0b25a8367148bd2468717b3571763a5cc599407e5c2","src/regalloc/context.rs":"794f9f0fb3b980feb3be57b95c152767cb318b81aca48c27197b01b7d529c48d","src/regalloc/diversion.rs":"cbb942a197081f9e537f3fed71a7ec6d6d1edc18b8536fa46a1dda316f46c776","src/regalloc/live_value_tracker.rs":"054efd9e8da0f33a158082f67a7c2c14f7c8632b1fc28d54941ca7bc9d5a46d6","src/regalloc/liveness.rs":"6886e52e68aee5b2e26fb0b6e073905e7fa963eb597657fc966e5758cda4c254","src/regalloc/liverange.rs":"3c6a34e35a912dce48fa9a579e82e14a7e64334d5572b0d74dbfbf42dd380804","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"7c73ca1f54559b1d9f8ce587bdc067e74f3d47901058f7ae1e9277516624236f","src/regalloc/register_set.rs":"e1554d01a3a5a13acc4e0092681eb3fc090d9c68eb71f8a9985c01c7a3f2e3e2","src/regalloc/reload.rs":"82040d3a3115f9117e11a77ee4e6d2437c1af84e0ee0b541ca286c5434c10e98","src/regalloc/solver.rs":"853c6f16f68e75add56981b132d92e556a94d8cbd13fed311df2d75da08de03a","src/regalloc/spilling.rs":"8ca113a149090c864df63e70a7f3a6c68c2edc655a5dd057724d63fc6319a8de","src/regalloc/virtregs.rs":"af5a0604557760a469f4aafd1047b73a8aaf5a1c19f6914a989a1a71662627a4","src/result.rs":"d43abf9b22c5ad772200889bba339bcc4455c7abb9f2f3a2af65fbbaf1130009","src/scoped_hash_map.rs":"102797c380a588f7c16d26bf3b6c9cff28d37c2d8168a382b265194cd8969212","src/settings.rs":"18f3b43b5ec916b5969a62a6bbf0b7b8f039a5f7930e406bb7e8f181f2dc0d2d","src/simple_gvn.rs":"fae3d71f7ab684044d8710e2193f26bf81e4b8a6f28de87b5caf1ca95eedc7ff","src/simple_preopt.rs":"cfafd0398bba0b3e2b91b5bf10617bd4048ba2b22345b3e5bfc403239903960a","src/stack_layout.rs":"ce0b4b188cc46fa5070139124ffb2d263d44acd08703e7043a40b5c1afa952fb","src/timing.rs":"79acc12600ace2b144f1d7d82e01c023596e418a84042cf70ef93df928cdcabf","src/topo_order.rs":"73ec442db1cc9a282cf9c5b715ad2f60c4d2872080c16fd04ef7091d56816fbd","src/unreachable_code.rs":"6fdea8f9afe9fbffe411bfef48fec7937cb41d51036fd190a3d0a5f0cc2894c6","src/verifier/cssa.rs":"8f41765d18474575faa7c44a0345549dabe0af07141e2f004a7db1c67486ce77","src/verifier/flags.rs":"0665b4cbeef762c3871ba3cc55b0b1a27c513e25cbd3f93a725aa3d636a23c72","src/verifier/liveness.rs":"6e827f05461bd6fb21b0ce99f02fae374f2d6ea6e7e14ba61e88983a1c6fac4b","src/verifier/locations.rs":"a83f7d58118a838651c80f55e2455736e79235691692488d8431b77be8093a58","src/verifier/mod.rs":"88e89da3a893a2c31c56596f49a0b5e4f4c92766115d661eb1f770d562454ac0","src/write.rs":"02995cbc87e2b15ed4021b88bcb36782975bedacc89282c5129923d20b4abc37"},"package":"4437ec8212686e6cdacfea75aaedb4ab8b013869be1e8693a4cb97a60f135035"}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen/Cargo.toml
+++ b/third_party/rust/cranelift-codegen/Cargo.toml
@@ -7,32 +7,32 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cranelift-codegen"
-version = "0.20.0"
+version = "0.23.0"
 authors = ["The Cranelift Project Developers"]
 build = "build.rs"
 description = "Low-level code generator library"
 documentation = "https://cranelift.readthedocs.io/"
 readme = "README.md"
 keywords = ["compile", "compiler", "jit"]
 categories = ["no-std"]
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/CraneStation/cranelift"
 [dependencies.cranelift-bforest]
-version = "0.20.0"
+version = "0.23.0"
 default-features = false
 
 [dependencies.cranelift-entity]
-version = "0.20.0"
+version = "0.23.0"
 default-features = false
 
 [dependencies.failure]
 version = "0.1.1"
 features = ["derive"]
 default-features = false
 
 [dependencies.failure_derive]
@@ -40,26 +40,26 @@ version = "0.1.1"
 default-features = false
 
 [dependencies.hashmap_core]
 version = "0.1.9"
 optional = true
 
 [dependencies.log]
 version = "0.4.4"
-features = ["release_max_level_warn"]
 default-features = false
 
 [dependencies.target-lexicon]
-version = "0.0.3"
+version = "0.2.0"
 default-features = false
 [build-dependencies.cranelift-codegen-meta]
-version = "0.20.0"
+version = "0.23.0"
 
 [features]
 core = ["hashmap_core"]
 default = ["std"]
 std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"]
+testing_hooks = []
 [badges.maintenance]
 status = "experimental"
 
 [badges.travis-ci]
 repository = "CraneStation/cranelift"
--- a/third_party/rust/cranelift-codegen/LICENSE
+++ b/third_party/rust/cranelift-codegen/LICENSE
@@ -212,8 +212,9 @@ with the conditions of Sections 4(a), 4(
 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.
+
--- a/third_party/rust/cranelift-codegen/build.rs
+++ b/third_party/rust/cranelift-codegen/build.rs
@@ -15,41 +15,44 @@
 //     A setting for conditional compilation of isa targets. Possible values can be "native" or
 //     known isa targets separated by ','.
 //
 // The build script expects to be run from the directory where this build.rs file lives. The
 // current directory is used to find the sources.
 
 extern crate cranelift_codegen_meta as meta;
 
+use meta::isa::Isa;
 use std::env;
 use std::process;
 
+use std::time::Instant;
+
 fn main() {
+    let start_time = Instant::now();
+
     let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
     let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
     let cranelift_targets = env::var("CRANELIFT_TARGETS").ok();
     let cranelift_targets = cranelift_targets.as_ref().map(|s| s.as_ref());
     let python = identify_python();
 
     // Configure isa targets cfg.
     match isa_targets(cranelift_targets, &target_triple) {
         Ok(isa_targets) => {
             for isa in &isa_targets {
-                println!("cargo:rustc-cfg=build_{}", isa.name());
+                println!("cargo:rustc-cfg=build_{}", isa.to_string());
             }
         }
         Err(err) => {
             eprintln!("Error: {}", err);
             process::exit(1);
         }
     }
 
-    println!("Build script generating files in {}", out_dir);
-
     let cur_dir = env::current_dir().expect("Can't access current working directory");
     let crate_dir = cur_dir.as_path();
 
     // Make sure we rebuild if this build script changes.
     // I guess that won't happen if you have non-UTF8 bytes in your path names.
     // The `build.py` script prints out its own dependencies.
     println!(
         "cargo:rerun-if-changed={}",
@@ -75,89 +78,53 @@ fn main() {
         process::exit(status.code().unwrap());
     }
 
     // DEVELOPMENT:
     // ------------------------------------------------------------------------
     // Now that the Python build process is complete, generate files that are
     // emitted by the `meta` crate.
     // ------------------------------------------------------------------------
-    if let Err(err) = meta::gen_types::generate("new_types.rs", &out_dir) {
+    let isas = meta::isa::define_all();
+
+    if let Err(err) = meta::gen_types::generate("types.rs", &out_dir) {
         eprintln!("Error: {}", err);
         process::exit(1);
     }
+
+    for isa in isas {
+        if let Err(err) = meta::gen_registers::generate(isa, "registers", &out_dir) {
+            eprintln!("Error: {}", err);
+            process::exit(1);
+        }
+    }
+
+    println!(
+        "cargo:warning=Cranelift meta-build step took {:?}",
+        Instant::now() - start_time
+    );
+    println!(
+        "cargo:warning=Meta-build script generated files in {}",
+        out_dir
+    );
 }
 
 fn identify_python() -> &'static str {
     for python in &["python", "python3", "python2.7"] {
         if process::Command::new(python)
             .arg("--version")
             .status()
             .is_ok()
         {
             return python;
         }
     }
     panic!("The Cranelift build requires Python (version 2.7 or version 3)");
 }
 
-/// Represents known ISA target.
-#[derive(Copy, Clone)]
-enum Isa {
-    Riscv,
-    X86,
-    Arm32,
-    Arm64,
-}
-
-impl Isa {
-    /// Creates isa target using name.
-    fn new(name: &str) -> Option<Self> {
-        Isa::all()
-            .iter()
-            .cloned()
-            .filter(|isa| isa.name() == name)
-            .next()
-    }
-
-    /// Creates isa target from arch.
-    fn from_arch(arch: &str) -> Option<Isa> {
-        Isa::all()
-            .iter()
-            .cloned()
-            .filter(|isa| isa.is_arch_applicable(arch))
-            .next()
-    }
-
-    /// Returns all supported isa targets.
-    fn all() -> [Isa; 4] {
-        [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
-    }
-
-    /// Returns name of the isa target.
-    fn name(&self) -> &'static str {
-        match *self {
-            Isa::Riscv => "riscv",
-            Isa::X86 => "x86",
-            Isa::Arm32 => "arm32",
-            Isa::Arm64 => "arm64",
-        }
-    }
-
-    /// Checks if arch is applicable for the isa target.
-    fn is_arch_applicable(&self, arch: &str) -> bool {
-        match *self {
-            Isa::Riscv => arch == "riscv",
-            Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
-            Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
-            Isa::Arm64 => arch == "aarch64",
-        }
-    }
-}
-
 /// Returns isa targets to configure conditional compilation.
 fn isa_targets(cranelift_targets: Option<&str>, target_triple: &str) -> Result<Vec<Isa>, String> {
     match cranelift_targets {
         Some("native") => Isa::from_arch(target_triple.split('-').next().unwrap())
             .map(|isa| vec![isa])
             .ok_or_else(|| {
                 format!(
                     "no supported isa found for target triple `{}`",
--- a/third_party/rust/cranelift-codegen/meta-python/base/formats.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/formats.py
@@ -45,17 +45,20 @@ FloatCond = InstructionFormat(floatcc, V
 
 IntSelect = InstructionFormat(intcc, VALUE, VALUE, VALUE)
 
 Jump = InstructionFormat(ebb, VARIABLE_ARGS)
 Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS)
 BranchInt = InstructionFormat(intcc, VALUE, ebb, VARIABLE_ARGS)
 BranchFloat = InstructionFormat(floatcc, VALUE, ebb, VARIABLE_ARGS)
 BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS)
-BranchTable = InstructionFormat(VALUE, entities.jump_table)
+BranchTable = InstructionFormat(VALUE, ebb, entities.jump_table)
+BranchTableEntry = InstructionFormat(VALUE, VALUE, uimm8, entities.jump_table)
+BranchTableBase = InstructionFormat(entities.jump_table)
+IndirectJump = InstructionFormat(VALUE, entities.jump_table)
 
 Call = InstructionFormat(func_ref, VARIABLE_ARGS)
 CallIndirect = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
 FuncAddr = InstructionFormat(func_ref)
 
 Load = InstructionFormat(memflags, VALUE, offset32)
 LoadComplex = InstructionFormat(memflags, VARIABLE_ARGS, offset32)
 Store = InstructionFormat(memflags, VALUE, VALUE, offset32)
--- a/third_party/rust/cranelift-codegen/meta-python/base/instructions.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/instructions.py
@@ -125,29 +125,66 @@ f = Operand('f', fflags)
 
 brff = Instruction(
         'brff', r"""
         Branch when condition is true in floating point CPU flags.
         """,
         ins=(Cond, f, EBB, args), is_branch=True)
 
 x = Operand('x', iB, doc='index into jump table')
+Entry = TypeVar('Entry', 'A scalar integer type', ints=True)
+entry = Operand('entry', Entry, doc='entry of jump table')
 JT = Operand('JT', entities.jump_table)
 br_table = Instruction(
         'br_table', r"""
         Indirect branch via jump table.
 
         Use ``x`` as an unsigned index into the jump table ``JT``. If a jump
         table entry is found, branch to the corresponding EBB. If no entry was
-        found fall through to the next instruction.
+        found or the index is out-of-bounds, branch to the given default EBB.
 
         Note that this branch instruction can't pass arguments to the targeted
         blocks. Split critical edges as needed to work around this.
         """,
-        ins=(x, JT), is_branch=True)
+        ins=(x, EBB, JT), is_branch=True, is_terminator=True)
+
+Size = Operand('Size', uimm8, 'Size in bytes')
+jump_table_entry = Instruction(
+    'jump_table_entry', r"""
+    Get an entry from a jump table.
+
+    Load a serialized ``entry`` from a jump table ``JT`` at a given index
+    ``addr`` with a specific ``Size``. The retrieved entry may need to be
+    decoded after loading, depending upon the jump table type used.
+
+    Currently, the only type supported is entries which are relative to the
+    base of the jump table.
+    """,
+    ins=(x, addr, Size, JT), outs=entry)
+
+jump_table_base = Instruction(
+    'jump_table_base', r"""
+    Get the absolute base address of a jump table.
+
+    This is used for jump tables wherein the entries are stored relative to
+    the base of jump table. In order to use these, generated code should first
+    load an entry using ``jump_table_entry``, then use this instruction to add
+    the relative base back to it.
+    """,
+    ins=JT, outs=addr)
+
+indirect_jump_table_br = Instruction(
+    'indirect_jump_table_br', r"""
+    Branch indirectly via a jump table entry.
+
+    Unconditionally jump via a jump table entry that was previously loaded
+    with the ``jump_table_entry`` instruction.
+    """,
+    ins=(addr, JT),
+    is_branch=True, is_indirect_branch=True, is_terminator=True)
 
 code = Operand('code', trapcode)
 trap = Instruction(
         'trap', r"""
         Terminate execution unconditionally.
         """,
         ins=code, is_terminator=True, can_trap=True)
 
@@ -192,16 +229,26 @@ x_return = Instruction(
         Return from the function.
 
         Unconditionally transfer control to the calling function, passing the
         provided return values. The list of return values must match the
         function signature's return types.
         """,
         ins=rvals, is_return=True, is_terminator=True)
 
+fallthrough_return = Instruction(
+        'fallthrough_return', r"""
+        Return from the function by fallthrough.
+
+        This is a specialized instruction for use where one wants to append
+        a custom epilogue, which will then perform the real return. This
+        instruction has no encoding.
+        """,
+        ins=rvals, is_return=True, is_terminator=True)
+
 FN = Operand(
         'FN',
         entities.func_ref,
         doc='function to call, declared by :inst:`function`')
 args = Operand('args', VARIABLE_ARGS, doc='call arguments')
 
 call = Instruction(
         'call', r"""
@@ -497,25 +544,25 @@ stack_addr = Instruction(
 #
 
 GV = Operand('GV', entities.global_value)
 
 global_value = Instruction(
         'global_value', r"""
         Compute the value of global GV.
         """,
-        ins=GV, outs=addr)
+        ins=GV, outs=a)
 
 # A specialized form of global_value instructions that only handles
 # symbolic names.
-globalsym_addr = Instruction(
-        'globalsym_addr', r"""
-        Compute the address of global GV, which is a symbolic name.
+symbol_value = Instruction(
+        'symbol_value', r"""
+        Compute the value of global GV, which is a symbolic value.
         """,
-        ins=GV, outs=addr)
+        ins=GV, outs=a)
 
 #
 # WebAssembly bounds-checked heap accesses.
 #
 
 HeapOffset = TypeVar('HeapOffset', 'An unsigned heap offset', ints=(32, 64))
 
 H = Operand('H', entities.heap)
@@ -792,17 +839,17 @@ hi = Operand('hi', TxN.half_vector(), do
 vsplit = Instruction(
         'vsplit', r"""
         Split a vector into two halves.
 
         Split the vector `x` into two separate values, each containing half of
         the lanes from ``x``. The result may be two scalars if ``x`` only had
         two lanes.
         """,
-        ins=x, outs=(lo, hi))
+        ins=x, outs=(lo, hi), is_ghost=True)
 
 Any128 = TypeVar(
         'Any128', 'Any scalar or vector type with as most 128 lanes',
         ints=True, floats=True, bools=True, scalars=True, simd=(1, 128))
 x = Operand('x', Any128, doc='Low-numbered lanes')
 y = Operand('y', Any128, doc='High-numbered lanes')
 a = Operand('a', Any128.double_vector(), doc='Concatenation of `x` and `y`')
 
@@ -812,17 +859,17 @@ vconcat = Instruction(
 
         Return a vector formed by concatenating ``x`` and ``y``. The resulting
         vector type has twice as many lanes as each of the inputs. The lanes of
         ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
         the high-numbered lanes of ``a``.
 
         It is possible to form a vector by concatenating two scalars.
         """,
-        ins=(x, y), outs=a)
+        ins=(x, y), outs=a, is_ghost=True)
 
 c = Operand('c', TxN.as_bool(), doc='Controlling vector')
 x = Operand('x', TxN, doc='Value to use where `c` is true')
 y = Operand('y', TxN, doc='Value to use where `c` is false')
 a = Operand('a', TxN)
 
 vselect = Instruction(
         'vselect', r"""
@@ -1082,17 +1129,17 @@ srem_imm = Instruction(
         Signed integer remainder with immediate divisor.
 
         This operation traps if the divisor is zero.
         """,
         ins=(x, Y), outs=a)
 
 irsub_imm = Instruction(
         'irsub_imm', """
-        Immediate reverse wrapping subtraction: :math:`a := Y - x \pmod{2^B}`.
+        Immediate reverse wrapping subtraction: :math:`a := Y - x \\pmod{2^B}`.
 
         Also works as integer negation when :math:`Y = 0`. Use :inst:`iadd_imm`
         with a negative immediate operand for the reverse immediate
         subtraction.
 
         Polymorphic over all scalar integer types, but does not support vector
         types.
         """,
@@ -1404,16 +1451,24 @@ sshr_imm = Instruction(
 
 #
 # Bit counting.
 #
 
 x = Operand('x', iB)
 a = Operand('a', iB)
 
+bitrev = Instruction(
+        'bitrev', r"""
+        Reverse the bits of a integer.
+
+        Reverses the bits in ``x``.
+        """,
+        ins=x, outs=a)
+
 clz = Instruction(
         'clz', r"""
         Count leading zero bits.
 
         Starting from the MSB in ``x``, count the number of zero bits before
         reaching the first one bit. When ``x`` is zero, returns the size of x
         in bits.
         """,
@@ -1949,17 +2004,17 @@ isplit = Instruction(
         Split an integer into low and high parts.
 
         Vectors of integers are split lane-wise, so the results have the same
         number of lanes as the input, but the lanes are half the size.
 
         Returns the low half of `x` and the high half of `x` as two independent
         values.
         """,
-        ins=x, outs=(lo, hi))
+        ins=x, outs=(lo, hi), is_ghost=True)
 
 
 NarrowInt = TypeVar(
         'NarrowInt', 'An integer type with lanes type to `i32`',
         ints=(8, 32), simd=True)
 lo = Operand('lo', NarrowInt)
 hi = Operand('hi', NarrowInt)
 a = Operand(
@@ -1969,11 +2024,11 @@ a = Operand(
 iconcat = Instruction(
         'iconcat', r"""
         Concatenate low and high bits to form a larger integer type.
 
         Vectors of integers are concatenated lane-wise such that the result has
         the same number of lanes as the inputs, but the lanes are twice the
         size.
         """,
-        ins=(lo, hi), outs=a)
+        ins=(lo, hi), outs=a, is_ghost=True)
 
 GROUP.close()
--- a/third_party/rust/cranelift-codegen/meta-python/base/legalize.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/legalize.py
@@ -21,19 +21,27 @@ from .instructions import bnot, band_not
 from .instructions import band_imm, bor_imm, bxor_imm
 from .instructions import icmp, icmp_imm, ifcmp, ifcmp_imm
 from .instructions import iconst, bint, select
 from .instructions import ishl, ishl_imm, sshr, sshr_imm, ushr, ushr_imm
 from .instructions import rotl, rotl_imm, rotr, rotr_imm
 from .instructions import f32const, f64const
 from .instructions import store, load
 from .instructions import br_table
+from .instructions import bitrev
 from cdsl.ast import Var
 from cdsl.xform import Rtl, XFormGroup
 
+try:
+    from typing import TYPE_CHECKING # noqa
+    if TYPE_CHECKING:
+        from cdsl.instructions import Instruction # noqa
+except ImportError:
+    TYPE_CHECKING = False
+
 
 narrow = XFormGroup('narrow', """
         Legalize instructions by narrowing.
 
         The transformations in the 'narrow' group work by expressing
         instructions in terms of smaller types. Operations on vector types are
         expressed in terms of vector types with fewer lanes, and integer
         operations are expressed in terms of smaller integer types.
@@ -83,30 +91,49 @@ expand.custom_legalize(insts.f32const, '
 expand.custom_legalize(insts.f64const, 'expand_fconst')
 
 # Custom expansions for stack memory accesses.
 expand.custom_legalize(insts.stack_load, 'expand_stack_load')
 expand.custom_legalize(insts.stack_store, 'expand_stack_store')
 
 x = Var('x')
 y = Var('y')
+z = Var('z')
 a = Var('a')
 a1 = Var('a1')
 a2 = Var('a2')
+a3 = Var('a3')
+a4 = Var('a4')
 b = Var('b')
 b1 = Var('b1')
 b2 = Var('b2')
+b3 = Var('b3')
+b4 = Var('b4')
 b_in = Var('b_in')
 b_int = Var('b_int')
 c = Var('c')
 c1 = Var('c1')
 c2 = Var('c2')
+c3 = Var('c3')
+c4 = Var('c4')
 c_in = Var('c_in')
 c_int = Var('c_int')
 d = Var('d')
+d1 = Var('d1')
+d2 = Var('d2')
+d3 = Var('d3')
+d4 = Var('d4')
+e = Var('e')
+e1 = Var('e1')
+e2 = Var('e2')
+e3 = Var('e3')
+e4 = Var('e4')
+f = Var('f')
+f1 = Var('f1')
+f2 = Var('f2')
 xl = Var('xl')
 xh = Var('xh')
 yl = Var('yl')
 yh = Var('yh')
 al = Var('al')
 ah = Var('ah')
 cc = Var('cc')
 ptr = Var('ptr')
@@ -150,25 +177,163 @@ narrow.legalize(
         Rtl(
             (xl, xh) << isplit(x),
             (yl, yh) << isplit(y),
             al << select(c, xl, yl),
             ah << select(c, xh, yh),
             a << iconcat(al, ah)
         ))
 
+
+def widen_one_arg(signed, op):
+    # type: (bool, Instruction) -> None
+    for int_ty in [types.i8, types.i16]:
+        if signed:
+            widen.legalize(
+                a << op.bind(int_ty)(b),
+                Rtl(
+                    x << sextend.i32(b),
+                    z << op.i32(x),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+        else:
+            widen.legalize(
+                a << op.bind(int_ty)(b),
+                Rtl(
+                    x << uextend.i32(b),
+                    z << op.i32(x),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+
+
+def widen_two_arg(signed, op):
+    # type: (bool, Instruction) -> None
+    for int_ty in [types.i8, types.i16]:
+        if signed:
+            widen.legalize(
+                a << op.bind(int_ty)(b, c),
+                Rtl(
+                    x << sextend.i32(b),
+                    y << sextend.i32(c),
+                    z << op.i32(x, y),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+        else:
+            widen.legalize(
+                a << op.bind(int_ty)(b, c),
+                Rtl(
+                    x << uextend.i32(b),
+                    y << uextend.i32(c),
+                    z << op.i32(x, y),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+
+
+def widen_imm(signed, op):
+    # type: (bool, Instruction) -> None
+    for int_ty in [types.i8, types.i16]:
+        if signed:
+            widen.legalize(
+                a << op.bind(int_ty)(b, c),
+                Rtl(
+                    x << sextend.i32(b),
+                    z << op.i32(x, c),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+        else:
+            widen.legalize(
+                a << op.bind(int_ty)(b, c),
+                Rtl(
+                    x << uextend.i32(b),
+                    z << op.i32(x, c),
+                    a << ireduce.bind(int_ty)(z)
+                ))
+
+
+# int ops
+for binop in [iadd, isub, imul, udiv, urem]:
+    widen_two_arg(False, binop)
+
+for binop in [sdiv, srem]:
+    widen_two_arg(True, binop)
+
+for binop in [iadd_imm, imul_imm, udiv_imm, urem_imm]:
+    widen_imm(False, binop)
+
+for binop in [sdiv_imm, srem_imm]:
+    widen_imm(True, binop)
+
+widen_imm(False, irsub_imm)
+
+# bit ops
+widen_one_arg(False, bnot)
+
+for binop in [band, bor, bxor, band_not, bor_not, bxor_not]:
+    widen_two_arg(False, binop)
+
+for binop in [band_imm, bor_imm, bxor_imm]:
+    widen_imm(False, binop)
+
+widen_one_arg(False, insts.popcnt)
+
+for (int_ty, num) in [(types.i8, 24), (types.i16, 16)]:
+    widen.legalize(
+        a << insts.clz.bind(int_ty)(b),
+        Rtl(
+            c << uextend.i32(b),
+            d << insts.clz.i32(c),
+            e << iadd_imm(d, imm64(-num)),
+            a << ireduce.bind(int_ty)(e)
+        ))
+
+    widen.legalize(
+        a << insts.cls.bind(int_ty)(b),
+        Rtl(
+            c << sextend.i32(b),
+            d << insts.cls.i32(c),
+            e << iadd_imm(d, imm64(-num)),
+            a << ireduce.bind(int_ty)(e)
+        ))
+
+for (int_ty, num) in [(types.i8, 1 << 8), (types.i16, 1 << 16)]:
+    widen.legalize(
+        a << insts.ctz.bind(int_ty)(b),
+        Rtl(
+            c << uextend.i32(b),
+            # When `b` is zero, returns the size of x in bits.
+            d << bor_imm(c, imm64(num)),
+            e << insts.ctz.i32(d),
+            a << ireduce.bind(int_ty)(e)
+        ))
+
+# iconst
 for int_ty in [types.i8, types.i16]:
     widen.legalize(
         a << iconst.bind(int_ty)(b),
         Rtl(
             c << iconst.i32(b),
             a << ireduce.bind(int_ty)(c)
         ))
 
 widen.legalize(
+    a << uextend.i16.i8(b),
+    Rtl(
+        c << uextend.i32(b),
+        a << ireduce(c)
+    ))
+
+widen.legalize(
+    a << sextend.i16.i8(b),
+    Rtl(
+        c << sextend.i32(b),
+        a << ireduce(c)
+    ))
+
+
+widen.legalize(
     store.i8(flags, a, ptr, offset),
     Rtl(
         b << uextend.i32(a),
         insts.istore8(flags, b, ptr, offset)
     ))
 
 widen.legalize(
     store.i16(flags, a, ptr, offset),
@@ -186,91 +351,100 @@ widen.legalize(
 
 widen.legalize(
     a << load.i16(flags, ptr, offset),
     Rtl(
         b << insts.uload16.i32(flags, ptr, offset),
         a << ireduce(b)
     ))
 
-for binop in [iadd, isub, imul, udiv, band, bor, bxor]:
-    for int_ty in [types.i8, types.i16]:
-        widen.legalize(
-            a << binop.bind(int_ty)(x, y),
-            Rtl(
-                b << uextend.i32(x),
-                c << uextend.i32(y),
-                d << binop(b, c),
-                a << ireduce(d)
-            )
-        )
-
-for binop in [sdiv]:
-    for int_ty in [types.i8, types.i16]:
-        widen.legalize(
-            a << binop.bind(int_ty)(x, y),
-            Rtl(
-                b << sextend.i32(x),
-                c << sextend.i32(y),
-                d << binop(b, c),
-                a << ireduce(d)
-            )
-        )
-
-for unop in [bnot]:
-    for int_ty in [types.i8, types.i16]:
-        widen.legalize(
-            a << unop.bind(int_ty)(x),
-            Rtl(
-                b << sextend.i32(x),
-                d << unop(b),
-                a << ireduce(d)
-            )
-        )
-
-for binop in [iadd_imm, imul_imm, udiv_imm]:
-    for int_ty in [types.i8, types.i16]:
-        widen.legalize(
-            a << binop.bind(int_ty)(x, y),
-            Rtl(
-                b << uextend.i32(x),
-                c << binop(b, y),
-                a << ireduce(c)
-            )
-        )
-
-for binop in [sdiv_imm]:
-    for int_ty in [types.i8, types.i16]:
-        widen.legalize(
-            a << binop.bind(int_ty)(x, y),
-            Rtl(
-                b << sextend.i32(x),
-                c << binop(b, y),
-                a << ireduce(c)
-            )
-        )
-
 for int_ty in [types.i8, types.i16]:
     widen.legalize(
-        br_table.bind(int_ty)(x, y),
+        br_table.bind(int_ty)(x, y, z),
         Rtl(
             b << uextend.i32(x),
-            br_table(b, y),
+            br_table(b, y, z),
         )
     )
 
 for int_ty in [types.i8, types.i16]:
     widen.legalize(
         a << insts.bint.bind(int_ty)(b),
         Rtl(
             x << insts.bint.i32(b),
             a << ireduce.bind(int_ty)(x)
         )
     )
 
+for int_ty in [types.i8, types.i16]:
+    for op in [ushr_imm, ishl_imm]:
+        widen.legalize(
+            a << op.bind(int_ty)(b, c),
+            Rtl(
+                x << uextend.i32(b),
+                z << op.i32(x, c),
+                a << ireduce.bind(int_ty)(z)
+            ))
+
+    widen.legalize(
+        a << ishl.bind(int_ty)(b, c),
+        Rtl(
+            x << uextend.i32(b),
+            z << ishl.i32(x, c),
+            a << ireduce.bind(int_ty)(z)
+        ))
+
+    widen.legalize(
+        a << ushr.bind(int_ty)(b, c),
+        Rtl(
+            x << uextend.i32(b),
+            z << ushr.i32(x, c),
+            a << ireduce.bind(int_ty)(z)
+        ))
+
+    widen.legalize(
+        a << sshr.bind(int_ty)(b, c),
+        Rtl(
+            x << sextend.i32(b),
+            z << sshr.i32(x, c),
+            a << ireduce.bind(int_ty)(z)
+        ))
+
+    for w_cc in [
+        intcc.eq, intcc.ne, intcc.ugt, intcc.ult, intcc.uge, intcc.ule
+    ]:
+        widen.legalize(
+            a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
+            Rtl(
+                x << uextend.i32(b),
+                a << insts.icmp_imm(w_cc, x, c)
+            ))
+        widen.legalize(
+            a << insts.icmp.bind(int_ty)(w_cc, b, c),
+            Rtl(
+                x << uextend.i32(b),
+                y << uextend.i32(c),
+                a << insts.icmp.i32(w_cc, x, y)
+            ))
+    for w_cc in [intcc.sgt, intcc.slt, intcc.sge, intcc.sle]:
+        widen.legalize(
+            a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
+            Rtl(
+                x << sextend.i32(b),
+                a << insts.icmp_imm(w_cc, x, c)
+            ))
+        widen.legalize(
+            a << insts.icmp.bind(int_ty)(w_cc, b, c),
+            Rtl(
+                x << sextend.i32(b),
+                y << sextend.i32(c),
+                a << insts.icmp(w_cc, x, y)
+            )
+        )
+
 # Expand integer operations with carry for RISC architectures that don't have
 # the flags.
 expand.legalize(
         (a, c) << iadd_cout(x, y),
         Rtl(
             a << iadd(x, y),
             c << icmp(intcc.ult, a, x)
         ))
@@ -377,16 +551,125 @@ for inst_not,      inst in [
 # Expand bnot using xor.
 expand.legalize(
         a << bnot(x),
         Rtl(
             y << iconst(imm64(-1)),
             a << bxor(x, y)
         ))
 
+# Expand bitrev
+# Adapted from Stack Overflow.
+# https://stackoverflow.com/questions/746171/most-efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
+widen.legalize(
+        a << bitrev.i8(x),
+        Rtl(
+            a1 << band_imm(x, imm64(0xaa)),
+            a2 << ushr_imm(a1, imm64(1)),
+            a3 << band_imm(x, imm64(0x55)),
+            a4 << ishl_imm(a3, imm64(1)),
+            b << bor(a2, a4),
+            b1 << band_imm(b, imm64(0xcc)),
+            b2 << ushr_imm(b1, imm64(2)),
+            b3 << band_imm(b, imm64(0x33)),
+            b4 << ushr_imm(b3, imm64(2)),
+            c << bor(b2, b4),
+            c1 << band_imm(c, imm64(0xf0)),
+            c2 << ushr_imm(c1, imm64(4)),
+            c3 << band_imm(c, imm64(0x0f)),
+            c4 << ishl_imm(c3, imm64(4)),
+            a << bor(c2, c4),
+        ))
+
+widen.legalize(
+        a << bitrev.i16(x),
+        Rtl(
+            a1 << band_imm(x, imm64(0xaaaa)),
+            a2 << ushr_imm(a1, imm64(1)),
+            a3 << band_imm(x, imm64(0x5555)),
+            a4 << ishl_imm(a3, imm64(1)),
+            b << bor(a2, a4),
+            b1 << band_imm(b, imm64(0xcccc)),
+            b2 << ushr_imm(b1, imm64(2)),
+            b3 << band_imm(b, imm64(0x3333)),
+            b4 << ushr_imm(b3, imm64(2)),
+            c << bor(b2, b4),
+            c1 << band_imm(c, imm64(0xf0f0)),
+            c2 << ushr_imm(c1, imm64(4)),
+            c3 << band_imm(c, imm64(0x0f0f)),
+            c4 << ishl_imm(c3, imm64(4)),
+            d << bor(c2, c4),
+            d1 << band_imm(d, imm64(0xff00)),
+            d2 << ushr_imm(d1, imm64(8)),
+            d3 << band_imm(d, imm64(0x00ff)),
+            d4 << ishl_imm(d3, imm64(8)),
+            a << bor(d2, d4),
+        ))
+
+expand.legalize(
+        a << bitrev.i32(x),
+        Rtl(
+            a1 << band_imm(x, imm64(0xaaaaaaaa)),
+            a2 << ushr_imm(a1, imm64(1)),
+            a3 << band_imm(x, imm64(0x55555555)),
+            a4 << ishl_imm(a3, imm64(1)),
+            b << bor(a2, a4),
+            b1 << band_imm(b, imm64(0xcccccccc)),
+            b2 << ushr_imm(b1, imm64(2)),
+            b3 << band_imm(b, imm64(0x33333333)),
+            b4 << ushr_imm(b3, imm64(2)),
+            c << bor(b2, b4),
+            c1 << band_imm(c, imm64(0xf0f0f0f0)),
+            c2 << ushr_imm(c1, imm64(4)),
+            c3 << band_imm(c, imm64(0x0f0f0f0f)),
+            c4 << ishl_imm(c3, imm64(4)),
+            d << bor(c2, c4),
+            d1 << band_imm(d, imm64(0xff00ff00)),
+            d2 << ushr_imm(d1, imm64(8)),
+            d3 << band_imm(d, imm64(0x00ff00ff)),
+            d4 << ishl_imm(d3, imm64(8)),
+            e << bor(d2, d4),
+            e1 << ushr_imm(e, imm64(16)),
+            e2 << ishl_imm(e, imm64(16)),
+            a << bor(e1, e2),
+        ))
+
+expand.legalize(
+        a << bitrev.i64(x),
+        Rtl(
+            a1 << band_imm(x, imm64(0xaaaaaaaaaaaaaaaa)),
+            a2 << ushr_imm(a1, imm64(1)),
+            a3 << band_imm(x, imm64(0x5555555555555555)),
+            a4 << ishl_imm(a3, imm64(1)),
+            b << bor(a2, a4),
+            b1 << band_imm(b, imm64(0xcccccccccccccccc)),
+            b2 << ushr_imm(b1, imm64(2)),
+            b3 << band_imm(b, imm64(0x3333333333333333)),
+            b4 << ushr_imm(b3, imm64(2)),
+            c << bor(b2, b4),
+            c1 << band_imm(c, imm64(0xf0f0f0f0f0f0f0f0)),
+            c2 << ushr_imm(c1, imm64(4)),
+            c3 << band_imm(c, imm64(0x0f0f0f0f0f0f0f0f)),
+            c4 << ishl_imm(c3, imm64(4)),
+            d << bor(c2, c4),
+            d1 << band_imm(d, imm64(0xff00ff00ff00ff00)),
+            d2 << ushr_imm(d1, imm64(8)),
+            d3 << band_imm(d, imm64(0x00ff00ff00ff00ff)),
+            d4 << ishl_imm(d3, imm64(8)),
+            e << bor(d2, d4),
+            e1 << band_imm(e, imm64(0xffff0000ffff0000)),
+            e2 << ushr_imm(e1, imm64(16)),
+            e3 << band_imm(e, imm64(0x0000ffff0000ffff)),
+            e4 << ishl_imm(e3, imm64(16)),
+            f << bor(e2, e4),
+            f1 << ushr_imm(f, imm64(32)),
+            f2 << ishl_imm(f, imm64(32)),
+            a << bor(f1, f2),
+        ))
+
 # Floating-point sign manipulations.
 for ty,             minus_zero in [
         (types.f32, f32const(ieee32.bits(0x80000000))),
         (types.f64, f64const(ieee64.bits(0x8000000000000000)))]:
     expand.legalize(
             a << insts.fabs.bind(ty)(x),
             Rtl(
                 b << minus_zero,
--- a/third_party/rust/cranelift-codegen/meta-python/base/settings.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/settings.py
@@ -22,64 +22,30 @@ enable_verifier = BoolSetting(
         """
         Run the Cranelift IR verifier at strategic times during compilation.
 
         This makes compilation slower but catches many bugs. The verifier is
         disabled by default, except when reading Cranelift IR from a text file.
         """,
         default=True)
 
-call_conv = EnumSetting(
-        """
-        Default calling convention:
-
-        - fast: not-ABI-stable convention for best performance
-        - cold: not-ABI-stable convention for infrequently executed code
-        - system_v: System V-style convention used on many platforms
-        - windows_fastcall: Windows "fastcall" convention, also used for
-                            x64 and ARM
-        - baldrdash: SpiderMonkey WebAssembly convention
-        - probestack: specialized convention for the probestack function
-
-        The default calling convention may be overridden by individual
-        functions.
-        """,
-
-        'fast',
-        'cold',
-        'system_v',
-        'windows_fastcall',
-        'baldrdash',
-        'probestack'
-)
-
 # Note that Cranelift doesn't currently need an is_pie flag, because PIE is
 # just PIC where symbols can't be pre-empted, which can be expressed with the
 # `colocated` flag on external functions and global values.
 is_pic = BoolSetting("Enable Position-Independent Code generation")
 
 colocated_libcalls = BoolSetting(
         """
         Use colocated libcalls.
 
         Generate code that assumes that libcalls can be declared "colocated",
         meaning they will be defined along with the current function, such that
         they can use more efficient addressing.
         """)
 
-return_at_end = BoolSetting(
-        """
-        Generate functions with at most a single return instruction at the
-        end of the function.
-
-        This guarantees that functions do not have any internal return
-        instructions. Either they never return, or they have a single return
-        instruction at the end.
-        """)
-
 avoid_div_traps = BoolSetting(
         """
         Generate explicit checks around native division instructions to avoid
         their trapping.
 
         This is primarily used by SpiderMonkey which doesn't install a signal
         handler for SIGFPE, but expects a SIGILL trap for division by zero.
 
@@ -161,9 +127,18 @@ probestack_size_log2 = NumSetting(
 
         Stack frames larger than this size will have stack overflow checked
         by calling the probestack function.
 
         The default is 12, which translates to a size of 4096.
         """,
         default=12)
 
+#
+# Jump table options.
+#
+jump_tables_enabled = BoolSetting(
+        """
+        Enable the use of jump tables in generated machine code.
+        """,
+        default=True)
+
 group.close(globals())
--- a/third_party/rust/cranelift-codegen/meta-python/base/types.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/types.py
@@ -1,21 +1,24 @@
 """
 The base.types module predefines all the Cranelift scalar types.
 """
 from __future__ import absolute_import
 from cdsl.types import IntType, FloatType, BoolType, FlagsType
 
-#: Boolean.
-b1 = BoolType(1)    #: 1-bit bool. Type is abstract (can't be stored in mem)
+#: Abstract boolean (can't be stored in memory, use bint to convert to 0 or 1).
+b1 = BoolType(1)    #: 1-bit bool.
+
+#: Booleans used as SIMD elements (can be stored in memory, true is all-ones).
 b8 = BoolType(8)    #: 8-bit bool.
 b16 = BoolType(16)  #: 16-bit bool.
 b32 = BoolType(32)  #: 32-bit bool.
 b64 = BoolType(64)  #: 64-bit bool.
 
+# Integers.
 i8 = IntType(8)     #: 8-bit int.
 i16 = IntType(16)   #: 16-bit int.
 i32 = IntType(32)   #: 32-bit int.
 i64 = IntType(64)   #: 64-bit int.
 
 #: IEEE single precision.
 f32 = FloatType(
         32, """
--- a/third_party/rust/cranelift-codegen/meta-python/build.py
+++ b/third_party/rust/cranelift-codegen/meta-python/build.py
@@ -1,40 +1,36 @@
 # Second-level build script.
 #
 # This script is run from lib/codegen/build.rs to generate Rust files.
 
 from __future__ import absolute_import
 import argparse
 import isa
-import gen_types
 import gen_instr
 import gen_settings
 import gen_build_deps
 import gen_encoding
 import gen_legalizer
-import gen_registers
 import gen_binemit
 
 
 def main():
     # type: () -> None
     parser = argparse.ArgumentParser(
             description='Generate sources for Cranelift.')
     parser.add_argument('--out-dir', help='set output directory')
 
     args = parser.parse_args()
     out_dir = args.out_dir
 
     isas = isa.all_isas()
 
-    gen_types.generate(out_dir)
     gen_instr.generate(isas, out_dir)
     gen_settings.generate(isas, out_dir)
     gen_encoding.generate(isas, out_dir)
     gen_legalizer.generate(isas, out_dir)
-    gen_registers.generate(isas, out_dir)
     gen_binemit.generate(isas, out_dir)
     gen_build_deps.generate()
 
 
 if __name__ == "__main__":
     main()
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/ast.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/ast.py
@@ -518,20 +518,24 @@ class ConstantInt(Literal):
     """
 
     def __init__(self, kind, value):
         # type: (ImmediateKind, int) -> None
         super(ConstantInt, self).__init__(kind, value)
 
     def __str__(self):
         # type: () -> str
-        """
-        Get the Rust expression form of this constant.
-        """
-        return str(self.value)
+        # If the value is in the signed imm64 range, print it as-is.
+        if self.value >= -(2**63) and self.value < (2**63):
+            return str(self.value)
+        # Otherwise if the value is in the unsigned imm64 range, print its
+        # bitwise counterpart in the signed imm64 range.
+        if self.value >= (2**63) and self.value < (2**64):
+            return str(self.value - (2**64))
+        assert False, "immediate value not in signed or unsigned imm64 range"
 
 
 class ConstantBits(Literal):
     """
     A bitwise value of an immediate operand.
 
     This is used to create bitwise exact floating point constants using
     `ieee32.bits(0x80000000)`.
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/instructions.py
@@ -84,32 +84,38 @@ class Instruction(object):
     :param doc: Documentation string.
     :param ins: Tuple of input operands. This can be a mix of SSA value
                 operands and other operand kinds.
     :param outs: Tuple of output operands. The output operands must be SSA
                 values or `variable_args`.
     :param constraints: Tuple of instruction-specific TypeConstraints.
     :param is_terminator: This is a terminator instruction.
     :param is_branch: This is a branch instruction.
+    :param is_indirect_branch: This is an indirect branch instruction.
     :param is_call: This is a call instruction.
     :param is_return: This is a return instruction.
+    :param is_ghost: This is a ghost instruction, which has no encoding and no
+                     other register allocation constraints.
     :param can_trap: This instruction can trap.
     :param can_load: This instruction can load from memory.
     :param can_store: This instruction can store to memory.
     :param other_side_effects: Instruction has other side effects.
     """
 
     # Boolean instruction attributes that can be passed as keyword arguments to
     # the constructor. Map attribute name to doc comment for generated Rust
     # code.
     ATTRIBS = {
             'is_terminator': 'True for instructions that terminate the EBB.',
             'is_branch': 'True for all branch or jump instructions.',
+            'is_indirect_branch':
+            'True for all indirect branch or jump instructions.',
             'is_call': 'Is this a call instruction?',
             'is_return': 'Is this a return instruction?',
+            'is_ghost': 'Is this a ghost instruction?',
             'can_load': 'Can this instruction read from memory?',
             'can_store': 'Can this instruction write to memory?',
             'can_trap': 'Can this instruction cause a trap?',
             'other_side_effects':
             'Does this instruction have other side effects besides can_*',
             'writes_cpu_flags': 'Does this instruction write to CPU flags?',
             }
 
@@ -337,17 +343,17 @@ class Instruction(object):
 
     def fully_bound(self):
         # type: () -> Tuple[Instruction, Tuple[ValueType, ...]]
         """
         Verify that all typevars have been bound, and return a
         `(inst, typevars)` pair.
 
         This version in `Instruction` itself allows non-polymorphic
-        instructions to duck-type as `BoundInstruction`\s.
+        instructions to duck-type as `BoundInstruction`\\s.
         """
         assert not self.is_polymorphic, self
         return (self, ())
 
     def __call__(self, *args):
         # type: (*Expr) -> Apply
         """
         Create an `ast.Apply` AST node representing the application of this
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/isa.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/isa.py
@@ -311,44 +311,48 @@ class EncRecipe(object):
 
     For ISAs that use CPU flags in `iflags` and `fflags` value types, the
     `clobbers_flags` is used to indicate instruction encodings that clobbers
     the CPU flags, so they can't be used where a flag value is live.
 
     :param name: Short mnemonic name for this recipe.
     :param format: All encoded instructions must have this
             :py:class:`InstructionFormat`.
-    :param size: Number of bytes in the binary encoded instruction.
+    :param base_size: Base number of bytes in the binary encoded instruction.
+    :param compute_size: Function name to use when computing actual size.
     :param ins: Tuple of register constraints for value operands.
     :param outs: Tuple of register constraints for results.
     :param branch_range: `(origin, bits)` range for branches.
     :param clobbers_flags: This instruction clobbers `iflags` and `fflags`.
     :param instp: Instruction predicate.
     :param isap: ISA predicate.
     :param emit: Rust code for binary emission.
     """
 
     def __init__(
             self,
-            name,                 # type: str
-            format,               # type: InstructionFormat
-            size,                 # type: int
-            ins,                  # type: ConstraintSeq
-            outs,                 # type: ConstraintSeq
-            branch_range=None,    # type: BranchRange
-            clobbers_flags=True,  # type: bool
-            instp=None,           # type: PredNode
-            isap=None,            # type: PredNode
-            emit=None             # type: str
+            name,                     # type: str
+            format,                   # type: InstructionFormat
+            base_size,                # type: int
+            ins,                      # type: ConstraintSeq
+            outs,                     # type: ConstraintSeq
+            compute_size=None,        # type: str
+            branch_range=None,        # type: BranchRange
+            clobbers_flags=True,      # type: bool
+            instp=None,               # type: PredNode
+            isap=None,                # type: PredNode
+            emit=None                 # type: str
             ):
         # type: (...) -> None
         self.name = name
         self.format = format
-        assert size >= 0
-        self.size = size
+        assert base_size >= 0
+        self.base_size = base_size
+        self.compute_size = compute_size if compute_size is not None \
+            else 'base_size'
         self.branch_range = branch_range
         self.clobbers_flags = clobbers_flags
         self.instp = instp
         self.isap = isap
         self.emit = emit
         if instp:
             assert instp.predicate_context() == format
         self.number = None  # type: int
@@ -464,17 +468,17 @@ class Encoding(object):
                     typred = TypePredicate.typevar_check(self.inst, tv, vt)
                     instp = And.combine(instp, typred)
 
         self.cpumode = cpumode
         assert self.inst.format == recipe.format, (
                 "Format {} must match recipe: {}".format(
                     self.inst.format, recipe.format))
 
-        if self.inst.is_branch:
+        if self.inst.is_branch and not self.inst.is_indirect_branch:
             assert recipe.branch_range, (
                     'Recipe {} for {} must have a branch_range'
                     .format(recipe, self.inst.name))
 
         self.recipe = recipe
         self.encbits = encbits
 
         # Record specific predicates. Note that the recipe also has predicates.
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/predicates.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/predicates.py
@@ -239,17 +239,17 @@ class FieldPredicate(object):
 
     def rust_predicate(self, prec):
         # type: (int) -> str
         """
         Return a string of Rust code that evaluates this predicate.
         """
         # Prepend `field` to the predicate function arguments.
         args = (self.field.rust_name(),) + tuple(map(str, self.args))
-        return 'predicates::{}({})'.format(self.function, ', '.join(args))
+        return '::predicates::{}({})'.format(self.function, ', '.join(args))
 
 
 class IsEqual(FieldPredicate):
     """
     Instruction predicate that checks if an immediate instruction format field
     is equal to a constant value.
 
     :param field: `FormatField` to be checked.
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/registers.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/registers.py
@@ -82,17 +82,16 @@ class RegBank(object):
         self.isa = isa
         self.first_unit = 0
         self.units = units
         self.pressure_tracking = pressure_tracking
         self.prefix = prefix
         self.names = names
         self.classes = list()  # type: List[RegClass]
         self.toprcs = list()  # type: List[RegClass]
-        self.first_toprc_index = None  # type: int
 
         assert len(names) <= units
 
         if isa.regbanks:
             # Get the next free unit number.
             last = isa.regbanks[-1]
             u = last.first_unit + last.units
             align = units
@@ -243,17 +242,17 @@ class RegClass(object):
         The tuple can be used as a dictionary key to ensure that there are no
         duplicate register classes.
         """
         return (self.width, self.bitmask)
 
     def intersect(self, other):
         # type: (RegClass) -> RCTup
         """
-        Get a tuple representing the intersction of two register classes.
+        Get a tuple representing the intersection of two register classes.
 
         Returns `None` if the two classes are disjoint.
         """
         if self.width != other.width:
             return None
         intersection = self.bitmask & other.bitmask
         if intersection == 0:
             return None
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/test_ti.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/test_ti.py
@@ -93,17 +93,17 @@ def check_typing(got_or_err, expected, s
 
 
 def check_concrete_typing_rtl(var_types, rtl):
     # type: (VarTyping, Rtl) -> None
     """
     Check that a concrete type assignment var_types (Dict[Var, TypeVar]) is
     valid for an Rtl rtl. Specifically check that:
 
-    1) For each Var v \in rtl, v is defined in var_types
+    1) For each Var v \\in rtl, v is defined in var_types
 
     2) For all v, var_types[v] is a singleton type
 
     3) For each v, and each location u, where v is used with expected type
        tv_u, var_types[v].get_typeset() is a subset of
        subst(tv_u, m).get_typeset() where m is the substitution of
        formals->actuals we are building so far.
 
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/ti.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/ti.py
@@ -21,16 +21,24 @@ except ImportError:
     TYPE_CHECKING = False
     pass
 
 
 class TypeConstraint(object):
     """
     Base class for all runtime-emittable type constraints.
     """
+
+    def __init__(self, tv, tc):
+        # type: (TypeVar, Union[TypeVar, TypeSet]) -> None
+        """
+        Abstract "constructor" for linters
+        """
+        assert False, "Abstract"
+
     def translate(self, m):
         # type: (Union[TypeEnv, TypeMap]) -> TypeConstraint
         """
         Translate any TypeVars in the constraint according to the map or
         TypeEnv m
         """
         def translate_one(a):
             # type: (Any) -> Any
@@ -70,17 +78,17 @@ class TypeConstraint(object):
         """
         assert False, "Abstract"
 
     def tvs(self):
         # type: () -> Iterable[TypeVar]
         """
         Return the typevars contained in this constraint.
         """
-        return filter(lambda x:  isinstance(x, TypeVar), self._args())
+        return list(filter(lambda x: isinstance(x, TypeVar), self._args()))
 
     def is_trivial(self):
         # type: () -> bool
         """
         Return true if this constrain is statically decidable.
         """
         assert False, "Abstract"
 
@@ -414,28 +422,28 @@ class TypeEnv(object):
         """
         Normalize by:
             - collapsing any roots that don't correspond to a concrete TV AND
               have a single TV derived from them or equivalent to them
 
         E.g. if we have a root of the tree that looks like:
 
           typeof_a   typeof_b
-                 \  /
+                 \\  /
               typeof_x
                   |
                 half_width(1)
                   |
                   1
 
         we want to collapse the linear path between 1 and typeof_x. The
         resulting graph is:
 
           typeof_a   typeof_b
-                 \  /
+                 \\  /
               typeof_x
         """
         source_tvs = set([v.get_typevar() for v in self.vars])
         children = {}  # type: Dict[TypeVar, Set[TypeVar]]
         for v in self.type_map.values():
             if not v.is_derived:
                 continue
 
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/types.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/types.py
@@ -174,17 +174,17 @@ class SpecialType(ValueType):
     A concrete scalar type that is neither a vector nor a lane type.
 
     Special types cannot be used to form vectors.
     """
 
     def __init__(self, name, membytes, doc):
         # type: (str, int, str) -> None
         super(SpecialType, self).__init__(name, membytes, doc)
-        # Assign numbers starting from 1. (0 is VOID)
+        # Assign numbers starting from 1. (0 is INVALID)
         ValueType.all_special_types.append(self)
         self.number = len(ValueType.all_special_types)
         assert self.number < LANE_BASE, 'Too many special types'
 
     def __repr__(self):
         # type: () -> str
         return 'SpecialType({})'.format(self.name)
 
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/typevar.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/typevar.py
@@ -115,17 +115,17 @@ def interval_to_set(intv):
     assert lo <= hi
     return set([2**i for i in range(int_log2(lo), int_log2(hi)+1)])
 
 
 def legal_bool(bits):
     # type: (int) -> bool
     """
     True iff bits is a legal bit width for a bool type.
-    bits == 1 || bits \in { 8, 16, .. MAX_BITS }
+    bits == 1 || bits \\in { 8, 16, .. MAX_BITS }
     """
     return bits == 1 or \
         (bits >= 8 and bits <= MAX_BITS and is_power_of_two(bits))
 
 
 class TypeSet(object):
     """
     A set of types.
--- a/third_party/rust/cranelift-codegen/meta-python/cdsl/xform.py
+++ b/third_party/rust/cranelift-codegen/meta-python/cdsl/xform.py
@@ -108,17 +108,17 @@ class Rtl(object):
         """Return True iff every Var in the self has a singleton type."""
         return all(v.get_typevar().singleton_type() is not None
                    for v in self.vars())
 
     def cleanup_concrete_rtl(self):
         # type: (Rtl) -> None
         """
         Given that there is only 1 possible concrete typing T for self, assign
-        a singleton TV with type t=T[v] for each Var v \in self. Its an error
+        a singleton TV with type t=T[v] for each Var v \\in self. Its an error
         to call this on an Rtl with more than 1 possible typing. This modifies
         the Rtl in-place.
         """
         from .ti import ti_rtl, TypeEnv
         # 1) Infer the types of all vars in res
         typenv = get_type_env(ti_rtl(self, TypeEnv()))
         typenv.normalize()
         typenv = typenv.extract()
--- a/third_party/rust/cranelift-codegen/meta-python/gen_encoding.py
+++ b/third_party/rust/cranelift-codegen/meta-python/gen_encoding.py
@@ -17,18 +17,18 @@ This is the information available to us:
   This is needed for testing any secondary type variables.
 - A `PredicateView` reference for the ISA-specific settings for evaluating ISA
   predicates.
 - The currently active CPU mode is determined by the ISA.
 
 ## Level 1 table lookup
 
 The CPU mode provides the first table. The key is the instruction's controlling
-type variable. If the instruction is not polymorphic, use `VOID` for the type
-variable. The table values are level 2 tables.
+type variable. If the instruction is not polymorphic, use `INVALID` for the
+type variable. The table values are level 2 tables.
 
 ## Level 2 table lookup
 
 The level 2 table is keyed by the instruction's opcode. The table values are
 *encoding lists*.
 
 The two-level table lookup allows the level 2 tables to be much smaller with
 good locality. Code in any given function usually only uses a few different
@@ -677,25 +677,25 @@ def emit_level1_hashtable(cpumode, level
 
     with fmt.indented(
             'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
             .format(cpumode.name.upper(), offt, len(hash_table)), '];'):
         for level2 in hash_table:
             # Empty hash table entry. Include the default legalization action.
             if not level2:
                 fmt.format(
-                        'Level1Entry {{ ty: ir::types::VOID, log2len: !0, '
+                        'Level1Entry {{ ty: ir::types::INVALID, log2len: !0, '
                         'offset: 0, legalize: {} }},',
                         level1.legalize_code)
                 continue
 
             if level2.ty is not None:
                 tyname = level2.ty.rust_name()
             else:
-                tyname = 'ir::types::VOID'
+                tyname = 'ir::types::INVALID'
 
             lcode = cpumode.isa.legalize_code(level2.legalize)
 
             # Empty level 2 table: Only a specialized legalization action, no
             # actual table.
             # Set an offset that is out of bounds, but make sure it doesn't
             # overflow its type when adding `1<<log2len`.
             if level2.is_empty():
@@ -827,17 +827,18 @@ def emit_recipe_sizing(isa, fmt):
     Emit a table of encoding recipe code size information.
     """
     with fmt.indented(
             'static RECIPE_SIZING: [RecipeSizing; {}] = ['
             .format(len(isa.all_recipes)), '];'):
         for r in isa.all_recipes:
             fmt.comment('Code size information for recipe {}:'.format(r.name))
             with fmt.indented('RecipeSizing {', '},'):
-                fmt.format('bytes: {},', r.size)
+                fmt.format('base_size: {},', r.base_size)
+                fmt.format('compute_size: {},', r.compute_size)
                 if r.branch_range:
                     fmt.format(
                         'branch_range: '
                         'Some(BranchRange {{ origin: {}, bits: {} }}),',
                         *r.branch_range)
                 else:
                     fmt.line('branch_range: None,')
 
--- a/third_party/rust/cranelift-codegen/meta-python/gen_instr.py
+++ b/third_party/rust/cranelift-codegen/meta-python/gen_instr.py
@@ -102,21 +102,20 @@ def gen_arguments_method(fmt, is_mut):
         fmt.match(m)
 
 
 def gen_instruction_data(fmt):
     # type: (srcgen.Formatter) -> None
     """
     Generate the InstructionData enum.
 
-    Every variant must contain `opcode` and `ty` fields. An instruction that
-    doesn't produce a value should have its `ty` field set to `VOID`. The size
-    of `InstructionData` should be kept at 16 bytes on 64-bit architectures. If
-    more space is needed to represent an instruction, use a `Box<AuxData>` to
-    store the additional information out of line.
+    Every variant must contain an `opcode` field. The size of `InstructionData`
+    should be kept at 16 bytes on 64-bit architectures. If more space is needed
+    to represent an instruction, use a `Box<AuxData>` to store the additional
+    information out of line.
     """
 
     fmt.line('#[derive(Clone, Debug)]')
     fmt.line('#[allow(missing_docs)]')
     with fmt.indented('pub enum InstructionData {', '}'):
         for f in InstructionFormat.all_formats:
             with fmt.indented('{} {{'.format(f.name), '},'):
                 fmt.line('opcode: Opcode,')
@@ -701,17 +700,17 @@ def gen_inst_builder(inst, fmt):
         # Arguments for instruction constructor.
         args = ['Opcode::' + inst.camel_name]
 
         if inst.is_polymorphic and not inst.use_typevar_operand:
             # This was an explicit method argument.
             args.append(inst.ctrl_typevar.name)
         elif not inst.is_polymorphic:
             # No controlling type variable needed.
-            args.append('types::VOID')
+            args.append('types::INVALID')
         else:
             assert inst.is_polymorphic and inst.use_typevar_operand
             # Infer the controlling type variable from the input operands.
             opnum = inst.value_opnums[inst.format.typevar_operand]
             fmt.line(
                     'let ctrl_typevar = self.data_flow_graph().value_type({});'
                     .format(inst.ins[opnum].name))
             # The format constructor will resolve the result types from the
deleted file mode 100644
--- a/third_party/rust/cranelift-codegen/meta-python/gen_registers.py
+++ /dev/null
@@ -1,109 +0,0 @@
-"""
-Generate register bank descriptions for each ISA.
-"""
-
-from __future__ import absolute_import
-import srcgen
-
-try:
-    from typing import Sequence, List  # noqa
-    from cdsl.isa import TargetISA  # noqa
-    from cdsl.registers import RegBank, RegClass  # noqa
-except ImportError:
-    pass
-
-
-def gen_regbank(regbank, fmt):
-    # type: (RegBank, srcgen.Formatter) -> None
-    """
-    Emit a static data definition for regbank.
-    """
-    with fmt.indented('RegBank {', '},'):
-        fmt.format('name: "{}",', regbank.name)
-        fmt.format('first_unit: {},', regbank.first_unit)
-        fmt.format('units: {},', regbank.units)
-        fmt.format(
-                'names: &[{}],',
-                ', '.join('"{}"'.format(n) for n in regbank.names))
-        fmt.format('prefix: "{}",', regbank.prefix)
-        fmt.format('first_toprc: {},', regbank.toprcs[0].index)
-        fmt.format('num_toprcs: {},', len(regbank.toprcs))
-        fmt.format(
-                'pressure_tracking: {},',
-                'true' if regbank.pressure_tracking else 'false')
-
-
-def gen_regbank_units(regbank, fmt):
-    # type: (RegBank, srcgen.Formatter) -> None
-    """
-    Emit constants for all the register units in `regbank`.
-    """
-    for unit in range(regbank.units):
-        v = unit + regbank.first_unit
-        if unit < len(regbank.names):
-            fmt.format("{} = {},", regbank.names[unit], v)
-        else:
-            fmt.format("{}{} = {},", regbank.prefix, unit, v)
-
-
-def gen_regclass(rc, fmt):
-    # type: (RegClass, srcgen.Formatter) -> None
-    """
-    Emit a static data definition for a register class.
-    """
-    with fmt.indented(
-            'pub static {}_DATA: RegClassData = RegClassData {{'
-            .format(rc.name), '};'):
-        fmt.format('name: "{}",', rc.name)
-        fmt.format('index: {},', rc.index)
-        fmt.format('width: {},', rc.width)
-        fmt.format('bank: {},', rc.bank.index)
-        fmt.format('toprc: {},', rc.toprc.index)
-        fmt.format('first: {},', rc.bank.first_unit + rc.start())
-        fmt.format('subclasses: 0x{:x},', rc.subclass_mask())
-        mask = ', '.join('0x{:08x}'.format(x) for x in rc.mask())
-        fmt.format('mask: [{}],', mask)
-        fmt.line('info: &INFO,')
-    # Also emit a convenient reference for use by hand-written code.
-    fmt.line('#[allow(dead_code)]')
-    fmt.format('pub static {0}: RegClass = &{0}_DATA;', rc.name)
-
-
-def gen_isa(isa, fmt):
-    # type: (TargetISA, srcgen.Formatter) -> None
-    """
-    Generate register tables for isa.
-    """
-    if not isa.regbanks:
-        print('cargo:warning={} has no register banks'.format(isa.name))
-
-    with fmt.indented('pub static INFO: RegInfo = RegInfo {', '};'):
-        # Bank descriptors.
-        with fmt.indented('banks: &[', '],'):
-            for regbank in isa.regbanks:
-                gen_regbank(regbank, fmt)
-        with fmt.indented('classes: &[', '],'):
-            for rc in isa.regclasses:
-                fmt.format('&{}_DATA,', rc.name)
-
-    # Register class descriptors.
-    for rc in isa.regclasses:
-        gen_regclass(rc, fmt)
-
-    # Emit constants for all the register units.
-    fmt.line('#[allow(dead_code, non_camel_case_types)]')
-    fmt.line('#[derive(Clone, Copy)]')
-    with fmt.indented('pub enum RU {', '}'):
-        for regbank in isa.regbanks:
-            gen_regbank_units(regbank, fmt)
-    with fmt.indented('impl Into<RegUnit> for RU {', '}'):
-        with fmt.indented('fn into(self) -> RegUnit {', '}'):
-            fmt.line('self as RegUnit')
-
-
-def generate(isas, out_dir):
-    # type: (Sequence[TargetISA], str) -> None
-    for isa in isas:
-        fmt = srcgen.Formatter()
-        gen_isa(isa, fmt)
-        fmt.update_file('registers-{}.rs'.format(isa.name), out_dir)
deleted file mode 100644
--- a/third_party/rust/cranelift-codegen/meta-python/gen_types.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""
-Generate sources with type info.
-
-This generates a `types.rs` file which is included in
-`lib/codegen/ir/types.rs`. The file provides constant definitions for the most
-commonly used types, including all of the scalar types.
-
-This ensures that Python and Rust use the same type numbering.
-"""
-from __future__ import absolute_import
-import srcgen
-from cdsl.types import ValueType
-import base.types  # noqa
-
-try:
-    from typing import Iterable  # noqa
-except ImportError:
-    pass
-
-
-def emit_type(ty, fmt):
-    # type: (ValueType, srcgen.Formatter) -> None
-    """
-    Emit a constant definition of a single value type.
-    """
-    name = ty.name.upper()
-    fmt.doc_comment(ty.__doc__)
-    fmt.line(
-            'pub const {}: Type = Type({:#x});'
-            .format(name, ty.number))
-    fmt.line()
-
-
-def emit_vectors(bits, fmt):
-    # type: (int, srcgen.Formatter) -> None
-    """
-    Emit definition for all vector types with `bits` total size.
-    """
-    size = bits // 8
-    for ty in ValueType.all_lane_types:
-        mb = ty.membytes
-        if mb == 0 or mb >= size:
-            continue
-        emit_type(ty.by(size // mb), fmt)
-
-
-def emit_types(fmt):
-    # type: (srcgen.Formatter) -> None
-    for spec in ValueType.all_special_types:
-        emit_type(spec, fmt)
-    for ty in ValueType.all_lane_types:
-        emit_type(ty, fmt)
-    # Emit vector definitions for common SIMD sizes.
-    emit_vectors(64, fmt)
-    emit_vectors(128, fmt)
-    emit_vectors(256, fmt)
-    emit_vectors(512, fmt)
-
-
-def generate(out_dir):
-    # type: (str) -> None
-    fmt = srcgen.Formatter()
-    emit_types(fmt)
-    fmt.update_file('types.rs', out_dir)
--- a/third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
@@ -88,138 +88,138 @@ def AIUPC():
 def LUI():
     # type: () -> int
     return 0b01101
 
 
 # R-type 32-bit instructions: These are mostly binary arithmetic instructions.
 # The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8)
 R = EncRecipe(
-        'R', Binary, size=4, ins=(GPR, GPR), outs=GPR,
+        'R', Binary, base_size=4, ins=(GPR, GPR), outs=GPR,
         emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
 
 # R-type with an immediate shift amount instead of rs2.
 Rshamt = EncRecipe(
-        'Rshamt', BinaryImm, size=4, ins=GPR, outs=GPR,
+        'Rshamt', BinaryImm, base_size=4, ins=GPR, outs=GPR,
         emit='put_rshamt(bits, in_reg0, imm.into(), out_reg0, sink);')
 
 # R-type encoding of an integer comparison.
 Ricmp = EncRecipe(
-        'Ricmp', IntCompare, size=4, ins=(GPR, GPR), outs=GPR,
+        'Ricmp', IntCompare, base_size=4, ins=(GPR, GPR), outs=GPR,
         emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
 
 Ii = EncRecipe(
-        'Ii', BinaryImm, size=4, ins=GPR, outs=GPR,
+        'Ii', BinaryImm, base_size=4, ins=GPR, outs=GPR,
         instp=IsSignedInt(BinaryImm.imm, 12),
         emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
 
 # I-type instruction with a hardcoded %x0 rs1.
 Iz = EncRecipe(
-        'Iz', UnaryImm, size=4, ins=(), outs=GPR,
+        'Iz', UnaryImm, base_size=4, ins=(), outs=GPR,
         instp=IsSignedInt(UnaryImm.imm, 12),
         emit='put_i(bits, 0, imm.into(), out_reg0, sink);')
 
 # I-type encoding of an integer comparison.
 Iicmp = EncRecipe(
-        'Iicmp', IntCompareImm, size=4, ins=GPR, outs=GPR,
+        'Iicmp', IntCompareImm, base_size=4, ins=GPR, outs=GPR,
         instp=IsSignedInt(IntCompareImm.imm, 12),
         emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
 
 # I-type encoding for `jalr` as a return instruction. We won't use the
 # immediate offset.
 # The variable return values are not encoded.
 Iret = EncRecipe(
-        'Iret', MultiAry, size=4, ins=(), outs=(),
+        'Iret', MultiAry, base_size=4, ins=(), outs=(),
         emit='''
         // Return instructions are always a jalr to %x1.
         // The return address is provided as a special-purpose link argument.
         put_i(
             bits,
             1, // rs1 = %x1
             0, // no offset.
             0, // rd = %x0: no address written.
             sink,
         );
         ''')
 
 # I-type encoding for `jalr` as a call_indirect.
 Icall = EncRecipe(
-        'Icall', CallIndirect, size=4, ins=GPR, outs=(),
+        'Icall', CallIndirect, base_size=4, ins=GPR, outs=(),
         emit='''
         // call_indirect instructions are jalr with rd=%x1.
         put_i(
             bits,
             in_reg0,
             0, // no offset.
             1, // rd = %x1: link register.
             sink,
         );
         ''')
 
 
 # Copy of a GPR is implemented as addi x, 0.
 Icopy = EncRecipe(
-        'Icopy', Unary, size=4, ins=GPR, outs=GPR,
+        'Icopy', Unary, base_size=4, ins=GPR, outs=GPR,
         emit='put_i(bits, in_reg0, 0, out_reg0, sink);')
 
 # Same for a GPR regmove.
 Irmov = EncRecipe(
-        'Irmov', RegMove, size=4, ins=GPR, outs=(),
+        'Irmov', RegMove, base_size=4, ins=GPR, outs=(),
         emit='put_i(bits, src, 0, dst, sink);')
 
 # U-type instructions have a 20-bit immediate that targets bits 12-31.
 U = EncRecipe(
-        'U', UnaryImm, size=4, ins=(), outs=GPR,
+        'U', UnaryImm, base_size=4, ins=(), outs=GPR,
         instp=IsSignedInt(UnaryImm.imm, 32, 12),
         emit='put_u(bits, imm.into(), out_reg0, sink);')
 
 # UJ-type unconditional branch instructions.
 UJ = EncRecipe(
-        'UJ', Jump, size=4, ins=(), outs=(), branch_range=(0, 21),
+        'UJ', Jump, base_size=4, ins=(), outs=(), branch_range=(0, 21),
         emit='''
         let dest = i64::from(func.offsets[destination]);
         let disp = dest - i64::from(sink.offset());
         put_uj(bits, disp, 0, sink);
         ''')
 
 UJcall = EncRecipe(
-        'UJcall', Call, size=4, ins=(), outs=(),
+        'UJcall', Call, base_size=4, ins=(), outs=(),
         emit='''
         sink.reloc_external(Reloc::RiscvCall,
                             &func.dfg.ext_funcs[func_ref].name,
                             0);
         // rd=%x1 is the standard link register.
         put_uj(bits, 0, 1, sink);
         ''')
 
 # SB-type branch instructions.
 SB = EncRecipe(
-        'SB', BranchIcmp, size=4,
+        'SB', BranchIcmp, base_size=4,
         ins=(GPR, GPR), outs=(),
         branch_range=(0, 13),
         emit='''
         let dest = i64::from(func.offsets[destination]);
         let disp = dest - i64::from(sink.offset());
         put_sb(bits, disp, in_reg0, in_reg1, sink);
         ''')
 
 # SB-type branch instruction with rs2 fixed to zero.
 SBzero = EncRecipe(
-        'SBzero', Branch, size=4,
+        'SBzero', Branch, base_size=4,
         ins=(GPR), outs=(),
         branch_range=(0, 13),
         emit='''
         let dest = i64::from(func.offsets[destination]);
         let disp = dest - i64::from(sink.offset());
         put_sb(bits, disp, in_reg0, 0, sink);
         ''')
 
 # Spill of a GPR.
 GPsp = EncRecipe(
-        'GPsp', Unary, size=4,
+        'GPsp', Unary, base_size=4,
         ins=GPR, outs=Stack(GPR),
         emit='unimplemented!();')
 
 # Fill of a GPR.
 GPfi = EncRecipe(
-        'GPfi', Unary, size=4,
+        'GPfi', Unary, base_size=4,
         ins=Stack(GPR), outs=GPR,
         emit='unimplemented!();')
--- a/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
@@ -168,17 +168,18 @@ enc_both(base.bxor.b1, r.rr, 0x31)
 enc_i32_i64(base.imul, r.rrx, 0x0f, 0xaf)
 enc_i32_i64(x86.sdivmodx, r.div, 0xf7, rrr=7)
 enc_i32_i64(x86.udivmodx, r.div, 0xf7, rrr=6)
 
 enc_i32_i64(x86.smulx, r.mulx, 0xf7, rrr=5)
 enc_i32_i64(x86.umulx, r.mulx, 0xf7, rrr=4)
 
 enc_i32_i64(base.copy, r.umr, 0x89)
-enc_both(base.copy.b1, r.umr, 0x89)
+for ty in [types.b1, types.i8, types.i16]:
+    enc_both(base.copy.bind(ty), r.umr, 0x89)
 
 # 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 [types.i8, types.i16, types.i32]:
     X86_32.enc(base.regmove.bind(ty), *r.rmov(0x89))
     X86_64.enc(base.regmove.bind(ty), *r.rmov.rex(0x89))
 X86_64.enc(base.regmove.i64, *r.rmov.rex(0x89, w=1))
 
@@ -296,37 +297,39 @@ for recipe in [r.st, r.stDisp8, r.stDisp
 # the corresponding st* recipes when a REX prefix is applied.
 for recipe in [r.st_abcd, r.stDisp8_abcd, r.stDisp32_abcd]:
     enc_both(base.istore8.i32.any, recipe, 0x88)
     enc_x86_64(base.istore8.i64.any, recipe, 0x88)
 
 enc_i32_i64(base.spill, r.spillSib32, 0x89)
 enc_i32_i64(base.regspill, r.regspill32, 0x89)
 
-# Use a 32-bit write for spilling `b1` to avoid constraining the permitted
-# registers.
+# 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.
-enc_both(base.spill.b1, r.spillSib32, 0x89)
-enc_both(base.regspill.b1, r.regspill32, 0x89)
+for ty in [types.b1, types.i8, types.i16]:
+    enc_both(base.spill.bind(ty), r.spillSib32, 0x89)
+    enc_both(base.regspill.bind(ty), r.regspill32, 0x89)
 
 for recipe in [r.ld, r.ldDisp8, r.ldDisp32]:
     enc_i32_i64_ld_st(base.load, True, recipe, 0x8b)
     enc_x86_64(base.uload32.i64, recipe, 0x8b)
     X86_64.enc(base.sload32.i64, *recipe.rex(0x63, w=1))
     enc_i32_i64_ld_st(base.uload16, True, recipe, 0x0f, 0xb7)
     enc_i32_i64_ld_st(base.sload16, True, recipe, 0x0f, 0xbf)
     enc_i32_i64_ld_st(base.uload8, True, recipe, 0x0f, 0xb6)
     enc_i32_i64_ld_st(base.sload8, True, recipe, 0x0f, 0xbe)
 
 enc_i32_i64(base.fill, r.fillSib32, 0x8b)
 enc_i32_i64(base.regfill, r.regfill32, 0x8b)
 
-# Load 32 bits from `b1` spill slots. See `spill.b1` above.
-enc_both(base.fill.b1, r.fillSib32, 0x8b)
-enc_both(base.regfill.b1, r.regfill32, 0x8b)
+# Load 32 bits from `b1`, `i8` and `i16` spill slots. See `spill.b1` above.
+for ty in [types.b1, types.i8, types.i16]:
+    enc_both(base.fill.bind(ty), r.fillSib32, 0x8b)
+    enc_both(base.regfill.bind(ty), r.regfill32, 0x8b)
 
 # Push and Pop
 X86_32.enc(x86.push.i32, *r.pushq(0x50))
 enc_x86_64(x86.push.i64, r.pushq, 0x50)
 
 X86_32.enc(x86.pop.i32, *r.popq(0x58))
 enc_x86_64(x86.pop.i64, r.popq, 0x58)
 
@@ -423,28 +426,28 @@ X86_64.enc(base.func_addr.i64, *r.pcrel_
 X86_64.enc(base.func_addr.i64, *r.got_fnaddr8.rex(0x8b, w=1),
            isap=is_pic)
 
 #
 # Global addresses.
 #
 
 # Non-PIC
-X86_32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8),
+X86_32.enc(base.symbol_value.i32, *r.gvaddr4(0xb8),
            isap=Not(is_pic))
-X86_64.enc(base.globalsym_addr.i64, *r.gvaddr8.rex(0xb8, w=1),
+X86_64.enc(base.symbol_value.i64, *r.gvaddr8.rex(0xb8, w=1),
            isap=Not(is_pic))
 
 # PIC, colocated
-X86_64.enc(base.globalsym_addr.i64, *r.pcrel_gvaddr8.rex(0x8d, w=1),
+X86_64.enc(base.symbol_value.i64, *r.pcrel_gvaddr8.rex(0x8d, w=1),
            isap=is_pic,
            instp=IsColocatedData())
 
 # PIC, non-colocated
-X86_64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1),
+X86_64.enc(base.symbol_value.i64, *r.got_gvaddr8.rex(0x8b, w=1),
            isap=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.
 #
@@ -503,16 +506,27 @@ X86_32.enc(base.brz.b1, *r.t8jccd_long(0
 X86_32.enc(base.brnz.b1, *r.t8jccd_long(0x85))
 
 enc_both(base.brz.b1, r.t8jccb_abcd, 0x74)
 enc_both(base.brz.b1, r.t8jccd_abcd, 0x84)
 enc_both(base.brnz.b1, r.t8jccb_abcd, 0x75)
 enc_both(base.brnz.b1, r.t8jccd_abcd, 0x85)
 
 #
+# Jump tables
+#
+X86_64.enc(base.jump_table_entry.i64.any.any, *r.jt_entry.rex(0x63, w=1))
+X86_32.enc(base.jump_table_entry.i32.any.any, *r.jt_entry(0x8b))
+
+X86_64.enc(base.jump_table_base.i64, *r.jt_base.rex(0x8d, w=1))
+X86_32.enc(base.jump_table_base.i32, *r.jt_base(0x8d))
+
+enc_x86_64(base.indirect_jump_table_br.i64, r.indirect_jmp, 0xff, rrr=4)
+X86_32.enc(base.indirect_jump_table_br.i32, *r.indirect_jmp(0xff, rrr=4))
+#
 # Trap as ud2
 #
 X86_32.enc(base.trap, *r.trap(0x0f, 0x0b))
 X86_64.enc(base.trap, *r.trap(0x0f, 0x0b))
 
 # Using a standard EncRecipe, not the TailRecipe.
 X86_32.enc(base.trapif, r.trapif, 0)
 X86_64.enc(base.trapif, r.trapif, 0)
@@ -562,18 +576,21 @@ X86_32.enc(base.bint.i32.b1, *r.urm_nofl
 X86_64.enc(base.bint.i64.b1, *r.urm_noflags.rex(0x0f, 0xb6))
 X86_64.enc(base.bint.i64.b1, *r.urm_noflags_abcd(0x0f, 0xb6))
 X86_64.enc(base.bint.i32.b1, *r.urm_noflags.rex(0x0f, 0xb6))
 X86_64.enc(base.bint.i32.b1, *r.urm_noflags_abcd(0x0f, 0xb6))
 
 # Numerical conversions.
 
 # Reducing an integer is a no-op.
+X86_32.enc(base.ireduce.i8.i16, r.null, 0)
 X86_32.enc(base.ireduce.i8.i32, r.null, 0)
 X86_32.enc(base.ireduce.i16.i32, r.null, 0)
+
+X86_64.enc(base.ireduce.i8.i16, r.null, 0)
 X86_64.enc(base.ireduce.i8.i32, r.null, 0)
 X86_64.enc(base.ireduce.i16.i32, r.null, 0)
 X86_64.enc(base.ireduce.i8.i64, r.null, 0)
 X86_64.enc(base.ireduce.i16.i64, r.null, 0)
 X86_64.enc(base.ireduce.i32.i64, r.null, 0)
 
 # TODO: Add encodings for cbw, cwde, cdqe, which are sign-extending
 # instructions for %al/%ax/%eax to %ax/%eax/%rax.
--- a/third_party/rust/cranelift-codegen/meta-python/isa/x86/recipes.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/x86/recipes.py
@@ -9,22 +9,23 @@ from cdsl.registers import RegClass
 from base.formats import Unary, UnaryIeee32, UnaryIeee64, UnaryImm, UnaryBool
 from base.formats import Binary, BinaryImm
 from base.formats import MultiAry, NullAry
 from base.formats import Trap, Call, CallIndirect, Store, Load
 from base.formats import IntCompare, IntCompareImm, FloatCompare
 from base.formats import IntCond, FloatCond
 from base.formats import IntSelect, IntCondTrap, FloatCondTrap
 from base.formats import Jump, Branch, BranchInt, BranchFloat
+from base.formats import BranchTableEntry, BranchTableBase, IndirectJump
 from base.formats import Ternary, FuncAddr, UnaryGlobalValue
 from base.formats import RegMove, RegSpill, RegFill, CopySpecial
 from base.formats import LoadComplex, StoreComplex
 from base.formats import StackLoad
-from .registers import GPR, ABCD, FPR, GPR_DEREF_SAFE, GPR_ZERO_DEREF_SAFE
-from .registers import GPR8, FPR8, GPR8_DEREF_SAFE, GPR8_ZERO_DEREF_SAFE, FLAG
+from .registers import GPR, ABCD, FPR
+from .registers import GPR8, FPR8, FLAG
 from .registers import StackGPR32, StackFPR32
 from .defs import supported_floatccs
 from .settings import use_sse41
 
 try:
     from typing import Tuple, Dict, Sequence, Any  # noqa
     from cdsl.instructions import InstructionFormat  # noqa
     from cdsl.isa import ConstraintSeq, BranchRange, PredNode, OperandConstraint  # noqa
@@ -107,18 +108,16 @@ def replace_put_op(emit, prefix):
         return None
     else:
         return emit.replace('PUT_OP', 'put_' + prefix.lower())
 
 
 # Register class mapping for no-REX instructions.
 NOREX_MAP = {
         GPR: GPR8,
-        GPR_DEREF_SAFE: GPR8_DEREF_SAFE,
-        GPR_ZERO_DEREF_SAFE: GPR8_ZERO_DEREF_SAFE,
         FPR: FPR8
     }
 
 
 def map_regs_norex(regs):
     # type: (Sequence[OperandConstraint]) -> Sequence[OperandConstraint]
     return tuple(NOREX_MAP.get(rc, rc) if isinstance(rc, RegClass) else rc
                  for rc in regs)
@@ -150,73 +149,76 @@ class TailRecipe:
     `EncRecipe` does it. Additionally, the text `PUT_OP` is substituted with
     the proper `put_*` function from the `x86/binemit.rs` module.
     """
 
     def __init__(
             self,
             name,                   # type: str
             format,                 # type: InstructionFormat
-            size,                   # type: int
+            base_size,              # type: int
             ins,                    # type: ConstraintSeq
             outs,                   # type: ConstraintSeq
             branch_range=None,      # type: int
             clobbers_flags=True,    # type: bool
             instp=None,             # type: PredNode
             isap=None,              # type: PredNode
             when_prefixed=None,     # type: TailRecipe
             requires_prefix=False,  # type: bool
-            emit=None               # type: str
+            emit=None,              # type: str
+            compute_size=None       # type: str
             ):
         # type: (...) -> None
         self.name = name
         self.format = format
-        self.size = size
+        self.base_size = base_size
         self.ins = ins
         self.outs = outs
         self.branch_range = branch_range
         self.clobbers_flags = clobbers_flags
         self.instp = instp
         self.isap = isap
         self.when_prefixed = when_prefixed
         self.requires_prefix = requires_prefix
         self.emit = emit
+        self.compute_size = compute_size
 
         # Cached recipes, keyed by name prefix.
         self.recipes = dict()  # type: Dict[str, EncRecipe]
 
     def __call__(self, *ops, **kwargs):
         # type: (*int, **int) -> Tuple[EncRecipe, int]
         """
         Create an encoding recipe and encoding bits for the opcode bytes in
         `ops`.
         """
         assert not self.requires_prefix, "Tail recipe requires REX prefix."
         rrr = kwargs.get('rrr', 0)
         w = kwargs.get('w', 0)
         name, bits = decode_ops(ops, rrr, w)
-        size = len(ops) + self.size
+        base_size = len(ops) + self.base_size
 
         # All branch ranges are relative to the end of the instruction.
         branch_range = None  # type BranchRange
         if self.branch_range is not None:
-            branch_range = (size, self.branch_range)
+            branch_range = (base_size, self.branch_range)
 
         if name not in self.recipes:
             recipe = EncRecipe(
                 name + self.name,
                 self.format,
-                size,
+                base_size,
                 ins=self.ins,
                 outs=self.outs,
                 branch_range=branch_range,
                 clobbers_flags=self.clobbers_flags,
                 instp=self.instp,
                 isap=self.isap,
-                emit=replace_put_op(self.emit, name))
+                emit=replace_put_op(self.emit, name),
+                compute_size=self.compute_size)
 
             recipe.ins = map_regs_norex(recipe.ins)
             recipe.outs = map_regs_norex(recipe.outs)
             self.recipes[name] = recipe
         return (self.recipes[name], bits)
 
     def rex(self, *ops, **kwargs):
         # type: (*int, **int) -> Tuple[EncRecipe, int]
@@ -231,35 +233,36 @@ class TailRecipe:
         # Use the prefixed alternative recipe when applicable.
         if self.when_prefixed:
             return self.when_prefixed.rex(*ops, **kwargs)
 
         rrr = kwargs.get('rrr', 0)
         w = kwargs.get('w', 0)
         name, bits = decode_ops(ops, rrr, w)
         name = 'Rex' + name
-        size = 1 + len(ops) + self.size
+        base_size = 1 + len(ops) + self.base_size
 
         # All branch ranges are relative to the end of the instruction.
         branch_range = None  # type BranchRange
         if self.branch_range is not None:
-            branch_range = (size, self.branch_range)
+            branch_range = (base_size, self.branch_range)
 
         if name not in self.recipes:
             recipe = EncRecipe(
                 name + self.name,
                 self.format,
-                size,
+                base_size,
                 ins=self.ins,
                 outs=self.outs,
                 branch_range=branch_range,
                 clobbers_flags=self.clobbers_flags,
                 instp=self.instp,
                 isap=self.isap,
-                emit=replace_put_op(self.emit, name))
+                emit=replace_put_op(self.emit, name),
+                compute_size=self.compute_size)
             self.recipes[name] = recipe
 
         return (self.recipes[name], bits)
 
     @staticmethod
     def check_names(globs):
         # type: (Dict[str, Any]) -> None
         for name, obj in globs.items():
@@ -271,480 +274,492 @@ def floatccs(iform):
     # type: (InstructionFormat) -> PredNode
     """
     Return an instruction predicate that checks in `iform.cond` is one of the
     directly supported floating point condition codes.
     """
     return Or(*(IsEqual(iform.cond, cc) for cc in supported_floatccs))
 
 
+def valid_scale(iform):
+    # type: (InstructionFormat) -> PredNode
+    """
+    Return an instruction predicate that checks if `iform.imm` is a valid
+    `scale` for a SIB byte.
+    """
+    return Or(IsEqual(iform.imm, 1),
+              IsEqual(iform.imm, 2),
+              IsEqual(iform.imm, 4),
+              IsEqual(iform.imm, 8))
+
+
 # A null unary instruction that takes a GPR register. Can be used for identity
 # copies and no-op conversions.
-null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='')
+null = EncRecipe('null', Unary, base_size=0, ins=GPR, outs=0, emit='')
 
 # XX opcode, no ModR/M.
 trap = TailRecipe(
-        'trap', Trap, size=0, ins=(), outs=(),
+        'trap', Trap, base_size=0, ins=(), outs=(),
         emit='''
         sink.trap(code, func.srclocs[inst]);
         PUT_OP(bits, BASE_REX, sink);
         ''')
 
 # Macro: conditional jump over a ud2.
 trapif = EncRecipe(
-        'trapif', IntCondTrap, size=4, ins=FLAG.rflags, outs=(),
+        'trapif', IntCondTrap, base_size=4, ins=FLAG.rflags, outs=(),
         clobbers_flags=False,
         emit='''
         // Jump over a 2-byte ud2.
         sink.put1(0x70 | (icc2opc(cond.inverse()) as u8));
         sink.put1(2);
         // ud2.
         sink.trap(code, func.srclocs[inst]);
         sink.put1(0x0f);
         sink.put1(0x0b);
         ''')
 
 trapff = EncRecipe(
-        'trapff', FloatCondTrap, size=4, ins=FLAG.rflags, outs=(),
+        'trapff', FloatCondTrap, base_size=4, ins=FLAG.rflags, outs=(),
         clobbers_flags=False,
         instp=floatccs(FloatCondTrap),
         emit='''
         // Jump over a 2-byte ud2.
         sink.put1(0x70 | (fcc2opc(cond.inverse()) as u8));
         sink.put1(2);
         // ud2.
         sink.trap(code, func.srclocs[inst]);
         sink.put1(0x0f);
         sink.put1(0x0b);
         ''')
 
 
 # XX /r
 rr = TailRecipe(
-        'rr', Binary, size=1, ins=(GPR, GPR), outs=0,
+        'rr', Binary, base_size=1, ins=(GPR, GPR), outs=0,
         emit='''
         PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
         modrm_rr(in_reg0, in_reg1, sink);
         ''')
 
 # XX /r with operands swapped. (RM form).
 rrx = TailRecipe(
-        'rrx', Binary, size=1, ins=(GPR, GPR), outs=0,
+        'rrx', Binary, base_size=1, ins=(GPR, GPR), outs=0,
         emit='''
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_rr(in_reg1, in_reg0, sink);
         ''')
 
 # XX /r with FPR ins and outs. A form.
 fa = TailRecipe(
-        'fa', Binary, size=1, ins=(FPR, FPR), outs=0,
+        'fa', Binary, base_size=1, ins=(FPR, FPR), outs=0,
         emit='''
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_rr(in_reg1, in_reg0, sink);
         ''')
 
 # XX /r with FPR ins and outs. A form with input operands swapped.
 fax = TailRecipe(
-        'fax', Binary, size=1, ins=(FPR, FPR), outs=1,
+        'fax', Binary, base_size=1, ins=(FPR, FPR), outs=1,
         emit='''
         PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
         modrm_rr(in_reg0, in_reg1, sink);
         ''')
 
 # XX /n for a unary operation with extension bits.
 ur = TailRecipe(
-        'ur', Unary, size=1, ins=GPR, outs=0,
+        'ur', Unary, base_size=1, ins=GPR, outs=0,
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         ''')
 
 # XX /r, but for a unary operator with separate input/output register, like
 # copies. MR form, preserving flags.
 umr = TailRecipe(
-        'umr', Unary, size=1, ins=GPR, outs=GPR,
+        'umr', Unary, base_size=1, ins=GPR, outs=GPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
         modrm_rr(out_reg0, in_reg0, sink);
         ''')
 
 # Same as umr, but with FPR -> GPR registers.
 rfumr = TailRecipe(
-        'rfumr', Unary, size=1, ins=FPR, outs=GPR,
+        'rfumr', Unary, base_size=1, ins=FPR, outs=GPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
         modrm_rr(out_reg0, in_reg0, sink);
         ''')
 
 # XX /r, but for a unary operator with separate input/output register.
 # RM form. Clobbers FLAGS.
 urm = TailRecipe(
-        'urm', Unary, size=1, ins=GPR, outs=GPR,
+        'urm', Unary, base_size=1, ins=GPR, outs=GPR,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r. Same as urm, but doesn't clobber FLAGS.
 urm_noflags = TailRecipe(
-        'urm_noflags', Unary, size=1, ins=GPR, outs=GPR,
+        'urm_noflags', Unary, base_size=1, ins=GPR, outs=GPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r. Same as urm_noflags, but input limited to ABCD.
 urm_noflags_abcd = TailRecipe(
-        'urm_noflags_abcd', Unary, size=1, ins=ABCD, outs=GPR,
+        'urm_noflags_abcd', Unary, base_size=1, ins=ABCD, outs=GPR,
         when_prefixed=urm_noflags,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r, RM form, FPR -> FPR.
 furm = TailRecipe(
-        'furm', Unary, size=1, ins=FPR, outs=FPR,
+        'furm', Unary, base_size=1, ins=FPR, outs=FPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r, RM form, GPR -> FPR.
 frurm = TailRecipe(
-        'frurm', Unary, size=1, ins=GPR, outs=FPR,
+        'frurm', Unary, base_size=1, ins=GPR, outs=FPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r, RM form, FPR -> GPR.
 rfurm = TailRecipe(
-        'rfurm', Unary, size=1, ins=FPR, outs=GPR,
+        'rfurm', Unary, base_size=1, ins=FPR, outs=GPR,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 # XX /r, RMI form for one of the roundXX SSE 4.1 instructions.
 furmi_rnd = TailRecipe(
-        'furmi_rnd', Unary, size=2, ins=FPR, outs=FPR,
+        'furmi_rnd', Unary, base_size=2, ins=FPR, outs=FPR,
         isap=use_sse41,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         sink.put1(match opcode {
             Opcode::Nearest => 0b00,
             Opcode::Floor => 0b01,
             Opcode::Ceil => 0b10,
             Opcode::Trunc => 0b11,
             x => panic!("{} unexpected for furmi_rnd", opcode),
         });
         ''')
 
 # XX /r, for regmove instructions.
 rmov = TailRecipe(
-        'rmov', RegMove, size=1, ins=GPR, outs=(),
+        'rmov', RegMove, base_size=1, ins=GPR, outs=(),
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(dst, src), sink);
         modrm_rr(dst, src, sink);
         ''')
 
 # XX /r, for regmove instructions (FPR version, RM encoded).
 frmov = TailRecipe(
-        'frmov', RegMove, size=1, ins=FPR, outs=(),
+        'frmov', RegMove, base_size=1, ins=FPR, outs=(),
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(src, dst), sink);
         modrm_rr(src, dst, sink);
         ''')
 
 # XX /n with one arg in %rcx, for shifts.
 rc = TailRecipe(
-        'rc', Binary, size=1, ins=(GPR, GPR.rcx), outs=0,
+        'rc', Binary, base_size=1, ins=(GPR, GPR.rcx), outs=0,
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         ''')
 
 # XX /n for division: inputs in %rax, %rdx, r. Outputs in %rax, %rdx.
 div = TailRecipe(
-        'div', Ternary, size=1,
+        'div', Ternary, base_size=1,
         ins=(GPR.rax, GPR.rdx, GPR), outs=(GPR.rax, GPR.rdx),
         emit='''
         sink.trap(TrapCode::IntegerDivisionByZero, func.srclocs[inst]);
         PUT_OP(bits, rex1(in_reg2), sink);
         modrm_r_bits(in_reg2, bits, sink);
         ''')
 
 # XX /n for {s,u}mulx: inputs in %rax, r. Outputs in %rdx(hi):%rax(lo)
 mulx = TailRecipe(
-        'mulx', Binary, size=1,
+        'mulx', Binary, base_size=1,
         ins=(GPR.rax, GPR), outs=(GPR.rax, GPR.rdx),
         emit='''
         PUT_OP(bits, rex1(in_reg1), sink);
         modrm_r_bits(in_reg1, bits, sink);
         ''')
 
 # XX /n ib with 8-bit immediate sign-extended.
 r_ib = TailRecipe(
-        'r_ib', BinaryImm, size=2, ins=GPR, outs=0,
+        'r_ib', BinaryImm, base_size=2, ins=GPR, outs=0,
         instp=IsSignedInt(BinaryImm.imm, 8),
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         let imm: i64 = imm.into();
         sink.put1(imm as u8);
         ''')
 
 # XX /n id with 32-bit immediate sign-extended.
 r_id = TailRecipe(
-        'r_id', BinaryImm, size=5, ins=GPR, outs=0,
+        'r_id', BinaryImm, base_size=5, ins=GPR, outs=0,
         instp=IsSignedInt(BinaryImm.imm, 32),
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         let imm: i64 = imm.into();
         sink.put4(imm as u32);
         ''')
 
 # XX /n id with 32-bit immediate sign-extended. UnaryImm version.
 u_id = TailRecipe(
-        'u_id', UnaryImm, size=5, ins=(), outs=GPR,
+        'u_id', UnaryImm, base_size=5, ins=(), outs=GPR,
         instp=IsSignedInt(UnaryImm.imm, 32),
         emit='''
         PUT_OP(bits, rex1(out_reg0), sink);
         modrm_r_bits(out_reg0, bits, sink);
         let imm: i64 = imm.into();
         sink.put4(imm as u32);
         ''')
 
 # XX+rd id unary with 32-bit immediate. Note no recipe predicate.
 pu_id = TailRecipe(
-        'pu_id', UnaryImm, size=4, ins=(), outs=GPR,
+        'pu_id', UnaryImm, base_size=4, ins=(), outs=GPR,
         emit='''
         // The destination register is encoded in the low bits of the opcode.
         // No ModR/M.
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         let imm: i64 = imm.into();
         sink.put4(imm as u32);
         ''')
 
 # XX+rd id unary with bool immediate. Note no recipe predicate.
 pu_id_bool = TailRecipe(
-        'pu_id_bool', UnaryBool, size=4, ins=(), outs=GPR,
+        'pu_id_bool', UnaryBool, base_size=4, ins=(), outs=GPR,
         emit='''
         // The destination register is encoded in the low bits of the opcode.
         // No ModR/M.
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         let imm: u32 = if imm { 1 } else { 0 };
         sink.put4(imm);
         ''')
 
 # XX+rd iq unary with 64-bit immediate.
 pu_iq = TailRecipe(
-        'pu_iq', UnaryImm, size=8, ins=(), outs=GPR,
+        'pu_iq', UnaryImm, base_size=8, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         let imm: i64 = imm.into();
         sink.put8(imm as u64);
         ''')
 
 # XX /n Unary with floating point 32-bit immediate equal to zero.
 f32imm_z = TailRecipe(
-    'f32imm_z', UnaryIeee32, size=1, ins=(), outs=FPR,
+    'f32imm_z', UnaryIeee32, base_size=1, ins=(), outs=FPR,
     instp=IsZero32BitFloat(UnaryIeee32.imm),
     emit='''
         PUT_OP(bits, rex2(out_reg0, out_reg0), sink);
         modrm_rr(out_reg0, out_reg0, sink);
     ''')
 
 # XX /n Unary with floating point 64-bit immediate equal to zero.
 f64imm_z = TailRecipe(
-    'f64imm_z', UnaryIeee64, size=1, ins=(), outs=FPR,
+    'f64imm_z', UnaryIeee64, base_size=1, ins=(), outs=FPR,
     instp=IsZero64BitFloat(UnaryIeee64.imm),
     emit='''
         PUT_OP(bits, rex2(out_reg0, out_reg0), sink);
         modrm_rr(out_reg0, out_reg0, sink);
     ''')
 
 pushq = TailRecipe(
-    'pushq', Unary, size=0, ins=GPR, outs=(),
+    'pushq', Unary, base_size=0, ins=GPR, outs=(),
     emit='''
     sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
     PUT_OP(bits | (in_reg0 & 7), rex1(in_reg0), sink);
     ''')
 
 popq = TailRecipe(
-    'popq', NullAry, size=0, ins=(), outs=GPR,
+    'popq', NullAry, base_size=0, ins=(), outs=GPR,
     emit='''
     PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
     ''')
 
 # XX /r, for regmove instructions.
 copysp = TailRecipe(
-        'copysp', CopySpecial, size=1, ins=(), outs=(),
+        'copysp', CopySpecial, base_size=1, ins=(), outs=(),
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, rex2(dst, src), sink);
         modrm_rr(dst, src, sink);
         ''')
 
 adjustsp = TailRecipe(
-    'adjustsp', Unary, size=1, ins=(GPR), outs=(),
+    'adjustsp', Unary, base_size=1, ins=(GPR), outs=(),
     emit='''
     PUT_OP(bits, rex2(RU::rsp.into(), in_reg0), sink);
     modrm_rr(RU::rsp.into(), in_reg0, sink);
     ''')
 
 adjustsp_ib = TailRecipe(
-    'adjustsp_ib', UnaryImm, size=2, ins=(), outs=(),
+    'adjustsp_ib', UnaryImm, base_size=2, ins=(), outs=(),
     instp=IsSignedInt(UnaryImm.imm, 8),
     emit='''
     PUT_OP(bits, rex1(RU::rsp.into()), sink);
     modrm_r_bits(RU::rsp.into(), bits, sink);
     let imm: i64 = imm.into();
     sink.put1(imm as u8);
     ''')
 
 adjustsp_id = TailRecipe(
-    'adjustsp_id', UnaryImm, size=5, ins=(), outs=(),
+    'adjustsp_id', UnaryImm, base_size=5, ins=(), outs=(),
     instp=IsSignedInt(UnaryImm.imm, 32),
     emit='''
     PUT_OP(bits, rex1(RU::rsp.into()), sink);
     modrm_r_bits(RU::rsp.into(), bits, sink);
     let imm: i64 = imm.into();
     sink.put4(imm as u32);
     ''')
 
 
 # XX+rd id with Abs4 function relocation.
 fnaddr4 = TailRecipe(
-        'fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
+        'fnaddr4', FuncAddr, base_size=4, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs4,
                             &func.dfg.ext_funcs[func_ref].name,
                             0);
         sink.put4(0);
         ''')
 
 # XX+rd iq with Abs8 function relocation.
 fnaddr8 = TailRecipe(
-        'fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
+        'fnaddr8', FuncAddr, base_size=8, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs8,
                             &func.dfg.ext_funcs[func_ref].name,
                             0);
         sink.put8(0);
         ''')
 
 # Similar to fnaddr4, but writes !0 (this is used by BaldrMonkey).
 allones_fnaddr4 = TailRecipe(
-        'allones_fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
+        'allones_fnaddr4', FuncAddr, base_size=4, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs4,
                             &func.dfg.ext_funcs[func_ref].name,
                             0);
         // Write the immediate as `!0` for the benefit of BaldrMonkey.
         sink.put4(!0);
         ''')
 
 # Similar to fnaddr8, but writes !0 (this is used by BaldrMonkey).
 allones_fnaddr8 = TailRecipe(
-        'allones_fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
+        'allones_fnaddr8', FuncAddr, base_size=8, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs8,
                             &func.dfg.ext_funcs[func_ref].name,
                             0);
         // Write the immediate as `!0` for the benefit of BaldrMonkey.
         sink.put8(!0);
         ''')
 
 pcrel_fnaddr8 = TailRecipe(
-        'pcrel_fnaddr8', FuncAddr, size=5, ins=(), outs=GPR,
+        'pcrel_fnaddr8', FuncAddr, base_size=5, ins=(), outs=GPR,
         # rex2 gets passed 0 for r/m register because the upper bit of
         # r/m doesnt get decoded when in rip-relative addressing mode.
         emit='''
         PUT_OP(bits, rex2(0, out_reg0), sink);
         modrm_riprel(out_reg0, sink);
         // The addend adjusts for the difference between the end of the
         // instruction and the beginning of the immediate field.
         sink.reloc_external(Reloc::X86PCRel4,
                             &func.dfg.ext_funcs[func_ref].name,
                             -4);
         sink.put4(0);
         ''')
 
 got_fnaddr8 = TailRecipe(
-        'got_fnaddr8', FuncAddr, size=5, ins=(), outs=GPR,
+        'got_fnaddr8', FuncAddr, base_size=5, ins=(), outs=GPR,
         # rex2 gets passed 0 for r/m register because the upper bit of
         # r/m doesnt get decoded when in rip-relative addressing mode.
         emit='''
         PUT_OP(bits, rex2(0, out_reg0), sink);
         modrm_riprel(out_reg0, sink);
         // The addend adjusts for the difference between the end of the
         // instruction and the beginning of the immediate field.
         sink.reloc_external(Reloc::X86GOTPCRel4,
                             &func.dfg.ext_funcs[func_ref].name,
                             -4);
         sink.put4(0);
         ''')
 
 
 # XX+rd id with Abs4 globalsym relocation.
 gvaddr4 = TailRecipe(
-        'gvaddr4', UnaryGlobalValue, size=4, ins=(), outs=GPR,
+        'gvaddr4', UnaryGlobalValue, base_size=4, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs4,
                             &func.global_values[global_value].symbol_name(),
                             0);
         sink.put4(0);
         ''')
 
 # XX+rd iq with Abs8 globalsym relocation.
 gvaddr8 = TailRecipe(
-        'gvaddr8', UnaryGlobalValue, size=8, ins=(), outs=GPR,
+        'gvaddr8', UnaryGlobalValue, base_size=8, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
         sink.reloc_external(Reloc::Abs8,
                             &func.global_values[global_value].symbol_name(),
                             0);
         sink.put8(0);
         ''')
 
 # XX+rd iq with PCRel4 globalsym relocation.
 pcrel_gvaddr8 = TailRecipe(
-        'pcrel_gvaddr8', UnaryGlobalValue, size=5, ins=(), outs=GPR,
+        'pcrel_gvaddr8', UnaryGlobalValue, base_size=5, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits, rex2(0, out_reg0), sink);
         modrm_rm(5, out_reg0, sink);
         // The addend adjusts for the difference between the end of the
         // instruction and the beginning of the immediate field.
         sink.reloc_external(Reloc::X86PCRel4,
                             &func.global_values[global_value].symbol_name(),
                             -4);
         sink.put4(0);
         ''')
 
 # XX+rd iq with Abs8 globalsym relocation.
 got_gvaddr8 = TailRecipe(
-        'got_gvaddr8', UnaryGlobalValue, size=5, ins=(), outs=GPR,
+        'got_gvaddr8', UnaryGlobalValue, base_size=5, ins=(), outs=GPR,
         emit='''
         PUT_OP(bits, rex2(0, out_reg0), sink);
         modrm_rm(5, out_reg0, sink);
         // The addend adjusts for the difference between the end of the
         // instruction and the beginning of the immediate field.
         sink.reloc_external(Reloc::X86GOTPCRel4,
                             &func.global_values[global_value].symbol_name(),
                             -4);
@@ -753,29 +768,29 @@ got_gvaddr8 = TailRecipe(
 
 #
 # Stack addresses.
 #
 # TODO: Alternative forms for 8-bit immediates, when applicable.
 #
 
 spaddr4_id = TailRecipe(
-        'spaddr4_id', StackLoad, size=6, ins=(), outs=GPR,
+        'spaddr4_id', StackLoad, base_size=6, ins=(), outs=GPR,
         emit='''
         let sp = StackRef::sp(stack_slot, &func.stack_slots);
         let base = stk_base(sp.base);
         PUT_OP(bits, rex2(out_reg0, base), sink);
         modrm_sib_disp8(out_reg0, sink);
         sib_noindex(base, sink);
         let imm : i32 = offset.into();
         sink.put4(sp.offset.checked_add(imm).unwrap() as u32);
         ''')
 
 spaddr8_id = TailRecipe(
-        'spaddr8_id', StackLoad, size=6, ins=(), outs=GPR,
+        'spaddr8_id', StackLoad, base_size=6, ins=(), outs=GPR,
         emit='''
         let sp = StackRef::sp(stack_slot, &func.stack_slots);
         let base = stk_base(sp.base);
         PUT_OP(bits, rex2(base, out_reg0), sink);
         modrm_sib_disp32(out_reg0, sink);
         sib_noindex(base, sink);
         let imm : i32 = offset.into();
         sink.put4(sp.offset.checked_add(imm).unwrap() as u32);
@@ -783,121 +798,160 @@ spaddr8_id = TailRecipe(
 
 
 #
 # Store recipes.
 #
 
 # XX /r register-indirect store with no offset.
 st = TailRecipe(
-        'st', Store, size=1, ins=(GPR, GPR_ZERO_DEREF_SAFE), outs=(),
+        'st', Store, base_size=1, ins=(GPR, GPR), outs=(),
         instp=IsEqual(Store.offset, 0),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_offset_for_in_reg_1",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_rm(in_reg1, in_reg0, sink);
+        if needs_offset(in_reg1) {
+            modrm_disp8(in_reg1, in_reg0, sink);
+            sink.put1(0);
+        } else {
+            modrm_rm(in_reg1, in_reg0, sink);
+        }
         ''')
 
 # XX /r register-indirect store with index and no offset.
 stWithIndex = TailRecipe(
-    'stWithIndex', StoreComplex, size=2,
-    ins=(GPR, GPR_ZERO_DEREF_SAFE, GPR_DEREF_SAFE),
+    'stWithIndex', StoreComplex, base_size=2,
+    ins=(GPR, GPR, GPR),
     outs=(),
     instp=IsEqual(StoreComplex.offset, 0),
     clobbers_flags=False,
+    compute_size="size_plus_maybe_offset_for_in_reg_1",
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
-    modrm_sib(in_reg0, sink);
-    sib(0, in_reg2, in_reg1, sink);
+    if needs_offset(in_reg1) {
+        modrm_sib_disp8(in_reg0, sink);
+        sib(0, in_reg2, in_reg1, sink);
+        sink.put1(0);
+    } else {
+        modrm_sib(in_reg0, sink);
+        sib(0, in_reg2, in_reg1, sink);
+    }
     ''')
 
 # XX /r register-indirect store with no offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 st_abcd = TailRecipe(
-        'st_abcd', Store, size=1, ins=(ABCD, GPR), outs=(),
+        'st_abcd', Store, base_size=1, ins=(ABCD, GPR), outs=(),
         instp=IsEqual(Store.offset, 0),
         when_prefixed=st,
         clobbers_flags=False,
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_rm(in_reg1, in_reg0, sink);
         ''')
 
 # XX /r register-indirect store with index and no offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 stWithIndex_abcd = TailRecipe(
-    'stWithIndex_abcd', StoreComplex, size=2,
-    ins=(ABCD, GPR_ZERO_DEREF_SAFE, GPR_DEREF_SAFE),
+    'stWithIndex_abcd', StoreComplex, base_size=2,
+    ins=(ABCD, GPR, GPR),
     outs=(),
     instp=IsEqual(StoreComplex.offset, 0),
     clobbers_flags=False,
+    compute_size="size_plus_maybe_offset_for_in_reg_1",
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
-    modrm_sib(in_reg0, sink);
-    sib(0, in_reg2, in_reg1, sink);
+    if needs_offset(in_reg1) {
+        modrm_sib_disp8(in_reg0, sink);
+        sib(0, in_reg2, in_reg1, sink);
+        sink.put1(0);
+    } else {
+        modrm_sib(in_reg0, sink);
+        sib(0, in_reg2, in_reg1, sink);
+    }
     ''')
 
 # XX /r register-indirect store of FPR with no offset.
 fst = TailRecipe(
-        'fst', Store, size=1, ins=(FPR, GPR_ZERO_DEREF_SAFE), outs=(),
+        'fst', Store, base_size=1, ins=(FPR, GPR), outs=(),
         instp=IsEqual(Store.offset, 0),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_offset_for_in_reg_1",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_rm(in_reg1, in_reg0, sink);
+        if needs_offset(in_reg1) {
+            modrm_disp8(in_reg1, in_reg0, sink);
+            sink.put1(0);
+        } else {
+            modrm_rm(in_reg1, in_reg0, sink);
+        }
         ''')
 # XX /r register-indirect store with index and no offset of FPR.
 fstWithIndex = TailRecipe(
-        'fstWithIndex', StoreComplex, size=2,
-        ins=(FPR, GPR_ZERO_DEREF_SAFE, GPR_DEREF_SAFE), outs=(),
+        'fstWithIndex', StoreComplex, base_size=2,
+        ins=(FPR, GPR, GPR), outs=(),
         instp=IsEqual(StoreComplex.offset, 0),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_offset_for_in_reg_1",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
-        modrm_sib(in_reg0, sink);
-        sib(0, in_reg2, in_reg1, sink);
+        if needs_offset(in_reg1) {
+            modrm_sib_disp8(in_reg0, sink);
+            sib(0, in_reg2, in_reg1, sink);
+            sink.put1(0);
+        } else {
+            modrm_sib(in_reg0, sink);
+            sib(0, in_reg2, in_reg1, sink);
+        }
         ''')
 
 # XX /r register-indirect store with 8-bit offset.
 stDisp8 = TailRecipe(
-        'stDisp8', Store, size=2, ins=(GPR, GPR_DEREF_SAFE), outs=(),
+        'stDisp8', Store, base_size=2, ins=(GPR, GPR), outs=(),
         instp=IsSignedInt(Store.offset, 8),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_sib_for_in_reg_1",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_disp8(in_reg1, in_reg0, sink);
+        if needs_sib_byte(in_reg1) {
+            modrm_sib_disp8(in_reg0, sink);
+            sib_noindex(in_reg1, sink);
+        } else {
+            modrm_disp8(in_reg1, in_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put1(offset as u8);
         ''')
 
 # XX /r register-indirect store with index and 8-bit offset.
 stWithIndexDisp8 = TailRecipe(
-    'stWithIndexDisp8', StoreComplex, size=3,
-    ins=(GPR, GPR, GPR_DEREF_SAFE),
+    'stWithIndexDisp8', StoreComplex, base_size=3,
+    ins=(GPR, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 8),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
@@ -905,100 +959,112 @@ stWithIndexDisp8 = TailRecipe(
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put1(offset as u8);
     ''')
 
 # XX /r register-indirect store with 8-bit offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 stDisp8_abcd = TailRecipe(
-        'stDisp8_abcd', Store, size=2, ins=(ABCD, GPR), outs=(),
+        'stDisp8_abcd', Store, base_size=2, ins=(ABCD, GPR), outs=(),
         instp=IsSignedInt(Store.offset, 8),
         when_prefixed=stDisp8,
         clobbers_flags=False,
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_disp8(in_reg1, in_reg0, sink);
         let offset: i32 = offset.into();
         sink.put1(offset as u8);
         ''')
 
 # XX /r register-indirect store with index and 8-bit offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 stWithIndexDisp8_abcd = TailRecipe(
-    'stWithIndexDisp8_abcd', StoreComplex, size=3,
-    ins=(ABCD, GPR, GPR_DEREF_SAFE),
+    'stWithIndexDisp8_abcd', StoreComplex, base_size=3,
+    ins=(ABCD, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 8),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
     modrm_sib_disp8(in_reg0, sink);
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put1(offset as u8);
     ''')
 
 # XX /r register-indirect store with 8-bit offset of FPR.
 fstDisp8 = TailRecipe(
-        'fstDisp8', Store, size=2, ins=(FPR, GPR_DEREF_SAFE), outs=(),
+        'fstDisp8', Store, base_size=2, ins=(FPR, GPR), outs=(),
         instp=IsSignedInt(Store.offset, 8),
         clobbers_flags=False,
+        compute_size='size_plus_maybe_sib_for_in_reg_1',
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_disp8(in_reg1, in_reg0, sink);
+        if needs_sib_byte(in_reg1) {
+            modrm_sib_disp8(in_reg0, sink);
+            sib_noindex(in_reg1, sink);
+        } else {
+            modrm_disp8(in_reg1, in_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put1(offset as u8);
         ''')
 
 # XX /r register-indirect store with index and 8-bit offset of FPR.
 fstWithIndexDisp8 = TailRecipe(
-    'fstWithIndexDisp8', StoreComplex, size=3,
-    ins=(FPR, GPR, GPR_DEREF_SAFE),
+    'fstWithIndexDisp8', StoreComplex, base_size=3,
+    ins=(FPR, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 8),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
     modrm_sib_disp8(in_reg0, sink);
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put1(offset as u8);
     ''')
 
 # XX /r register-indirect store with 32-bit offset.
 stDisp32 = TailRecipe(
-        'stDisp32', Store, size=5, ins=(GPR, GPR_DEREF_SAFE), outs=(),
+        'stDisp32', Store, base_size=5, ins=(GPR, GPR), outs=(),
         clobbers_flags=False,
+        compute_size='size_plus_maybe_sib_for_in_reg_1',
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_disp32(in_reg1, in_reg0, sink);
+        if needs_sib_byte(in_reg1) {
+            modrm_sib_disp32(in_reg0, sink);
+            sib_noindex(in_reg1, sink);
+        } else {
+            modrm_disp32(in_reg1, in_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put4(offset as u32);
         ''')
 
 # XX /r register-indirect store with index and 32-bit offset.
 stWithIndexDisp32 = TailRecipe(
-    'stWithIndexDisp32', StoreComplex, size=6,
-    ins=(GPR, GPR, GPR_DEREF_SAFE),
+    'stWithIndexDisp32', StoreComplex, base_size=6,
+    ins=(GPR, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 32),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
@@ -1006,123 +1072,129 @@ stWithIndexDisp32 = TailRecipe(
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put4(offset as u32);
     ''')
 
 # XX /r register-indirect store with 32-bit offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 stDisp32_abcd = TailRecipe(
-        'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=(),
+        'stDisp32_abcd', Store, base_size=5, ins=(ABCD, GPR), outs=(),
         when_prefixed=stDisp32,
         clobbers_flags=False,
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_disp32(in_reg1, in_reg0, sink);
         let offset: i32 = offset.into();
         sink.put4(offset as u32);
         ''')
 
 # XX /r register-indirect store with index and 32-bit offset.
 # Only ABCD allowed for stored value. This is for byte stores with no REX.
 stWithIndexDisp32_abcd = TailRecipe(
-    'stWithIndexDisp32_abcd', StoreComplex, size=6,
-    ins=(ABCD, GPR, GPR_DEREF_SAFE),
+    'stWithIndexDisp32_abcd', StoreComplex, base_size=6,
+    ins=(ABCD, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 32),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
     modrm_sib_disp32(in_reg0, sink);
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put4(offset as u32);
     ''')
 
 # XX /r register-indirect store with 32-bit offset of FPR.
 fstDisp32 = TailRecipe(
-        'fstDisp32', Store, size=5, ins=(FPR, GPR_DEREF_SAFE), outs=(),
+        'fstDisp32', Store, base_size=5, ins=(FPR, GPR), outs=(),
         clobbers_flags=False,
+        compute_size='size_plus_maybe_sib_for_in_reg_1',
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
-        modrm_disp32(in_reg1, in_reg0, sink);
+        if needs_sib_byte(in_reg1) {
+            modrm_sib_disp32(in_reg0, sink);
+            sib_noindex(in_reg1, sink);
+        } else {
+            modrm_disp32(in_reg1, in_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put4(offset as u32);
         ''')
 
 # XX /r register-indirect store with index and 32-bit offset of FPR.
 fstWithIndexDisp32 = TailRecipe(
-    'fstWithIndexDisp32', StoreComplex, size=6,
-    ins=(FPR, GPR, GPR_DEREF_SAFE),
+    'fstWithIndexDisp32', StoreComplex, base_size=6,
+    ins=(FPR, GPR, GPR),
     outs=(),
     instp=IsSignedInt(StoreComplex.offset, 32),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg1, in_reg0, in_reg2), sink);
     modrm_sib_disp32(in_reg0, sink);
     sib(0, in_reg2, in_reg1, sink);
     let offset: i32 = offset.into();
     sink.put4(offset as u32);
     ''')
 
 # Unary spill with SIB and 32-bit displacement.
 spillSib32 = TailRecipe(
-        'spillSib32', Unary, size=6, ins=GPR, outs=StackGPR32,
+        'spillSib32', Unary, base_size=6, ins=GPR, outs=StackGPR32,
         clobbers_flags=False,
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         let base = stk_base(out_stk0.base);
         PUT_OP(bits, rex2(base, in_reg0), sink);
         modrm_sib_disp32(in_reg0, sink);
         sib_noindex(base, sink);
         sink.put4(out_stk0.offset as u32);
         ''')
 
 # Like spillSib32, but targeting an FPR rather than a GPR.
 fspillSib32 = TailRecipe(
-        'fspillSib32', Unary, size=6, ins=FPR, outs=StackFPR32,
+        'fspillSib32', Unary, base_size=6, ins=FPR, outs=StackFPR32,
         clobbers_flags=False,
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         let base = stk_base(out_stk0.base);
         PUT_OP(bits, rex2(base, in_reg0), sink);
         modrm_sib_disp32(in_reg0, sink);
         sib_noindex(base, sink);
         sink.put4(out_stk0.offset as u32);
         ''')
 
 # Regspill using RSP-relative addressing.
 regspill32 = TailRecipe(
-        'regspill32', RegSpill, size=6, ins=GPR, outs=(),
+        'regspill32', RegSpill, base_size=6, ins=GPR, outs=(),
         clobbers_flags=False,
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         let dst = StackRef::sp(dst, &func.stack_slots);
         let base = stk_base(dst.base);
         PUT_OP(bits, rex2(base, src), sink);
         modrm_sib_disp32(src, sink);
         sib_noindex(base, sink);
         sink.put4(dst.offset as u32);
         ''')
 
 # Like regspill32, but targeting an FPR rather than a GPR.
 fregspill32 = TailRecipe(
-        'fregspill32', RegSpill, size=6, ins=FPR, outs=(),
+        'fregspill32', RegSpill, base_size=6, ins=FPR, outs=(),
         clobbers_flags=False,
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         let dst = StackRef::sp(dst, &func.stack_slots);
         let base = stk_base(dst.base);
         PUT_OP(bits, rex2(base, src), sink);
         modrm_sib_disp32(src, sink);
         sib_noindex(base, sink);
@@ -1130,469 +1202,558 @@ fregspill32 = TailRecipe(
         ''')
 
 #
 # Load recipes
 #
 
 # XX /r load with no offset.
 ld = TailRecipe(
-        'ld', Load, size=1, ins=(GPR_ZERO_DEREF_SAFE), outs=(GPR),
+        'ld', Load, base_size=1, ins=(GPR), outs=(GPR),
         instp=IsEqual(Load.offset, 0),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_offset_for_in_reg_0",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_rm(in_reg0, out_reg0, sink);
+        if needs_offset(in_reg0) {
+            modrm_disp8(in_reg0, out_reg0, sink);
+            sink.put1(0);
+        } else {
+            modrm_rm(in_reg0, out_reg0, sink);
+        }
         ''')
 
 # XX /r load with index and no offset.
 ldWithIndex = TailRecipe(
-    'ldWithIndex', LoadComplex, size=2,
-    ins=(GPR_ZERO_DEREF_SAFE, GPR_DEREF_SAFE),
+    'ldWithIndex', LoadComplex, base_size=2,
+    ins=(GPR, GPR),
     outs=(GPR),
     instp=IsEqual(LoadComplex.offset, 0),
     clobbers_flags=False,
+    compute_size="size_plus_maybe_offset_for_in_reg_0",
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
-    modrm_sib(out_reg0, sink);
-    sib(0, in_reg1, in_reg0, sink);
+    if needs_offset(in_reg0) {
+        modrm_sib_disp8(out_reg0, sink);
+        sib(0, in_reg1, in_reg0, sink);
+        sink.put1(0);
+    } else {
+        modrm_sib(out_reg0, sink);
+        sib(0, in_reg1, in_reg0, sink);
+    }
     ''')
 
 # XX /r float load with no offset.
 fld = TailRecipe(
-        'fld', Load, size=1, ins=(GPR_ZERO_DEREF_SAFE), outs=(FPR),
+        'fld', Load, base_size=1, ins=(GPR), outs=(FPR),
         instp=IsEqual(Load.offset, 0),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_offset_for_in_reg_0",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_rm(in_reg0, out_reg0, sink);
+        if needs_offset(in_reg0) {
+            modrm_disp8(in_reg0, out_reg0, sink);
+            sink.put1(0);
+        } else {
+            modrm_rm(in_reg0, out_reg0, sink);
+        }
         ''')
 
 # XX /r float load with index and no offset.
 fldWithIndex = TailRecipe(
-    'fldWithIndex', LoadComplex, size=2,
-    ins=(GPR_ZERO_DEREF_SAFE, GPR_DEREF_SAFE),
+    'fldWithIndex', LoadComplex, base_size=2,
+    ins=(GPR, GPR),
     outs=(FPR),
     instp=IsEqual(LoadComplex.offset, 0),
     clobbers_flags=False,
+    compute_size="size_plus_maybe_offset_for_in_reg_0",
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
-    modrm_sib(out_reg0, sink);
-    sib(0, in_reg1, in_reg0, sink);
+    if needs_offset(in_reg0) {
+        modrm_sib_disp8(out_reg0, sink);
+        sib(0, in_reg1, in_reg0, sink);
+        sink.put1(0);
+    } else {
+        modrm_sib(out_reg0, sink);
+        sib(0, in_reg1, in_reg0, sink);
+    }
     ''')
 
 # XX /r load with 8-bit offset.
 ldDisp8 = TailRecipe(
-        'ldDisp8', Load, size=2, ins=(GPR_DEREF_SAFE), outs=(GPR),
+        'ldDisp8', Load, base_size=2, ins=(GPR), outs=(GPR),
         instp=IsSignedInt(Load.offset, 8),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_sib_for_in_reg_0",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_disp8(in_reg0, out_reg0, sink);
+        if needs_sib_byte(in_reg0) {
+            modrm_sib_disp8(out_reg0, sink);
+            sib_noindex(in_reg0, sink);
+        } else {
+            modrm_disp8(in_reg0, out_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put1(offset as u8);
         ''')
 
 # XX /r load with index and 8-bit offset.
 ldWithIndexDisp8 = TailRecipe(
-    'ldWithIndexDisp8', LoadComplex, size=3,
-    ins=(GPR, GPR_DEREF_SAFE),
+    'ldWithIndexDisp8', LoadComplex, base_size=3,
+    ins=(GPR, GPR),
     outs=(GPR),
     instp=IsSignedInt(LoadComplex.offset, 8),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
     modrm_sib_disp8(out_reg0, sink);
     sib(0, in_reg1, in_reg0, sink);
     let offset: i32 = offset.into();
     sink.put1(offset as u8);
     ''')
 
 # XX /r float load with 8-bit offset.
 fldDisp8 = TailRecipe(
-        'fldDisp8', Load, size=2, ins=(GPR_DEREF_SAFE), outs=(FPR),
+        'fldDisp8', Load, base_size=2, ins=(GPR), outs=(FPR),
         instp=IsSignedInt(Load.offset, 8),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_sib_for_in_reg_0",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_disp8(in_reg0, out_reg0, sink);
+        if needs_sib_byte(in_reg0) {
+            modrm_sib_disp8(out_reg0, sink);
+            sib_noindex(in_reg0, sink);
+        } else {
+            modrm_disp8(in_reg0, out_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put1(offset as u8);
         ''')
 
 # XX /r float load with 8-bit offset.
 fldWithIndexDisp8 = TailRecipe(
-    'fldWithIndexDisp8', LoadComplex, size=3,
-    ins=(GPR, GPR_DEREF_SAFE),
+    'fldWithIndexDisp8', LoadComplex, base_size=3,
+    ins=(GPR, GPR),
     outs=(FPR),
     instp=IsSignedInt(LoadComplex.offset, 8),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
     modrm_sib_disp8(out_reg0, sink);
     sib(0, in_reg1, in_reg0, sink);
     let offset: i32 = offset.into();
     sink.put1(offset as u8);
     ''')
 
 # XX /r load with 32-bit offset.
 ldDisp32 = TailRecipe(
-        'ldDisp32', Load, size=5, ins=(GPR_DEREF_SAFE), outs=(GPR),
+        'ldDisp32', Load, base_size=5, ins=(GPR), outs=(GPR),
         instp=IsSignedInt(Load.offset, 32),
         clobbers_flags=False,
+        compute_size='size_plus_maybe_sib_for_in_reg_0',
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_disp32(in_reg0, out_reg0, sink);
+        if needs_sib_byte(in_reg0) {
+            modrm_sib_disp32(out_reg0, sink);
+            sib_noindex(in_reg0, sink);
+        } else {
+            modrm_disp32(in_reg0, out_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put4(offset as u32);
         ''')
 
 # XX /r load with index and 32-bit offset.
 ldWithIndexDisp32 = TailRecipe(
-    'ldWithIndexDisp32', LoadComplex, size=6,
-    ins=(GPR, GPR_DEREF_SAFE),
+    'ldWithIndexDisp32', LoadComplex, base_size=6,
+    ins=(GPR, GPR),
     outs=(GPR),
     instp=IsSignedInt(LoadComplex.offset, 32),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
     modrm_sib_disp32(out_reg0, sink);
     sib(0, in_reg1, in_reg0, sink);
     let offset: i32 = offset.into();
     sink.put4(offset as u32);
     ''')
 
 # XX /r float load with 32-bit offset.
 fldDisp32 = TailRecipe(
-        'fldDisp32', Load, size=5, ins=(GPR_DEREF_SAFE), outs=(FPR),
+        'fldDisp32', Load, base_size=5, ins=(GPR), outs=(FPR),
         instp=IsSignedInt(Load.offset, 32),
         clobbers_flags=False,
+        compute_size="size_plus_maybe_sib_for_in_reg_0",
         emit='''
         if !flags.notrap() {
             sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
         }
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
-        modrm_disp32(in_reg0, out_reg0, sink);
+        if needs_sib_byte(in_reg0) {
+            modrm_sib_disp32(out_reg0, sink);
+            sib_noindex(in_reg0, sink);
+        } else {
+            modrm_disp32(in_reg0, out_reg0, sink);
+        }
         let offset: i32 = offset.into();
         sink.put4(offset as u32);
         ''')
 
 # XX /r float load with index and 32-bit offset.
 fldWithIndexDisp32 = TailRecipe(
-    'fldWithIndexDisp32', LoadComplex, size=6,
-    ins=(GPR, GPR_DEREF_SAFE),
+    'fldWithIndexDisp32', LoadComplex, base_size=6,
+    ins=(GPR, GPR),
     outs=(FPR),
     instp=IsSignedInt(LoadComplex.offset, 32),
     clobbers_flags=False,
     emit='''
     if !flags.notrap() {
         sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
     }
     PUT_OP(bits, rex3(in_reg0, out_reg0, in_reg1), sink);
     modrm_sib_disp32(out_reg0, sink);
     sib(0, in_reg1, in_reg0, sink);
     let offset: i32 = offset.into();
     sink.put4(offset as u32);
     ''')
 
 # Unary fill with SIB and 32-bit displacement.
 fillSib32 = TailRecipe(
-        'fillSib32', Unary, size=6, ins=StackGPR32, outs=GPR,
+        'fillSib32', Unary, base_size=6, ins=StackGPR32, outs=GPR,
         clobbers_flags=False,
         emit='''
         let base = stk_base(in_stk0.base);
         PUT_OP(bits, rex2(base, out_reg0), sink);
         modrm_sib_disp32(out_reg0, sink);
         sib_noindex(base, sink);
         sink.put4(in_stk0.offset as u32);
         ''')
 
 # Like fillSib32, but targeting an FPR rather than a GPR.
 ffillSib32 = TailRecipe(
-        'ffillSib32', Unary, size=6, ins=StackFPR32, outs=FPR,
+        'ffillSib32', Unary, base_size=6, ins=StackFPR32, outs=FPR,
         clobbers_flags=False,
         emit='''
         let base = stk_base(in_stk0.base);
         PUT_OP(bits, rex2(base, out_reg0), sink);
         modrm_sib_disp32(out_reg0, sink);
         sib_noindex(base, sink);
         sink.put4(in_stk0.offset as u32);
         ''')
 
 # Regfill with RSP-relative 32-bit displacement.
 regfill32 = TailRecipe(
-        'regfill32', RegFill, size=6, ins=StackGPR32, outs=(),
+        'regfill32', RegFill, base_size=6, ins=StackGPR32, outs=(),
         clobbers_flags=False,
         emit='''
         let src = StackRef::sp(src, &func.stack_slots);
         let base = stk_base(src.base);
         PUT_OP(bits, rex2(base, dst), sink);
         modrm_sib_disp32(dst, sink);
         sib_noindex(base, sink);
         sink.put4(src.offset as u32);
         ''')
 
 # Like regfill32, but targeting an FPR rather than a GPR.
 fregfill32 = TailRecipe(
-        'fregfill32', RegFill, size=6, ins=StackFPR32, outs=(),
+        'fregfill32', RegFill, base_size=6, ins=StackFPR32, outs=(),
         clobbers_flags=False,
         emit='''
         let src = StackRef::sp(src, &func.stack_slots);
         let base = stk_base(src.base);
         PUT_OP(bits, rex2(base, dst), sink);
         modrm_sib_disp32(dst, sink);
         sib_noindex(base, sink);
         sink.put4(src.offset as u32);
         ''')
 
 #
 # Call/return
 #
 call_id = TailRecipe(
-        'call_id', Call, size=4, ins=(), outs=(),
+        'call_id', Call, base_size=4, ins=(), outs=(),
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         PUT_OP(bits, BASE_REX, sink);
         // The addend adjusts for the difference between the end of the
         // instruction and the beginning of the immediate field.
         sink.reloc_external(Reloc::X86CallPCRel4,
                             &func.dfg.ext_funcs[func_ref].name,
                             -4);
         sink.put4(0);
         ''')
 
 call_plt_id = TailRecipe(
-        'call_plt_id', Call, size=4, ins=(), outs=(),
+        'call_plt_id', Call, base_size=4, ins=(), outs=(),
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         PUT_OP(bits, BASE_REX, sink);
         sink.reloc_external(Reloc::X86CallPLTRel4,
                             &func.dfg.ext_funcs[func_ref].name,
                             -4);
         sink.put4(0);
         ''')
 
 call_r = TailRecipe(
-        'call_r', CallIndirect, size=1, ins=GPR, outs=(),
+        'call_r', CallIndirect, base_size=1, ins=GPR, outs=(),
         emit='''
         sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         ''')
 
 ret = TailRecipe(
-        'ret', MultiAry, size=0, ins=(), outs=(),
+        'ret', MultiAry, base_size=0, ins=(), outs=(),
         emit='''
         PUT_OP(bits, BASE_REX, sink);
         ''')
 
 #
 # Branches
 #
 jmpb = TailRecipe(
-        'jmpb', Jump, size=1, ins=(), outs=(),
+        'jmpb', Jump, base_size=1, ins=(), outs=(),
         branch_range=8,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, BASE_REX, sink);
         disp1(destination, func, sink);
         ''')
 
 jmpd = TailRecipe(
-        'jmpd', Jump, size=4, ins=(), outs=(),
+        'jmpd', Jump, base_size=4, ins=(), outs=(),
         branch_range=32,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits, BASE_REX, sink);
         disp4(destination, func, sink);
         ''')
 
 brib = TailRecipe(
-        'brib', BranchInt, size=1, ins=FLAG.rflags, outs=(),
+        'brib', BranchInt, base_size=1, ins=FLAG.rflags, outs=(),
         branch_range=8,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | icc2opc(cond), BASE_REX, sink);
         disp1(destination, func, sink);
         ''')
 
 brid = TailRecipe(
-        'brid', BranchInt, size=4, ins=FLAG.rflags, outs=(),
+        'brid', BranchInt, base_size=4, ins=FLAG.rflags, outs=(),
         branch_range=32,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | icc2opc(cond), BASE_REX, sink);
         disp4(destination, func, sink);
         ''')
 
 brfb = TailRecipe(
-        'brfb', BranchFloat, size=1, ins=FLAG.rflags, outs=(),
+        'brfb', BranchFloat, base_size=1, ins=FLAG.rflags, outs=(),
         branch_range=8,
         clobbers_flags=False,
         instp=floatccs(BranchFloat),
         emit='''
         PUT_OP(bits | fcc2opc(cond), BASE_REX, sink);
         disp1(destination, func, sink);
         ''')
 
 brfd = TailRecipe(
-        'brfd', BranchFloat, size=4, ins=FLAG.rflags, outs=(),
+        'brfd', BranchFloat, base_size=4, ins=FLAG.rflags, outs=(),
         branch_range=32,
         clobbers_flags=False,
         instp=floatccs(BranchFloat),
         emit='''
         PUT_OP(bits | fcc2opc(cond), BASE_REX, sink);
         disp4(destination, func, sink);
         ''')
 
+indirect_jmp = TailRecipe(
+        'indirect_jmp', IndirectJump, base_size=1, ins=GPR, outs=(),
+        clobbers_flags=False,
+        emit='''
+        PUT_OP(bits, rex1(in_reg0), sink);
+        modrm_r_bits(in_reg0, bits, sink);
+        ''')
+
+jt_entry = TailRecipe(
+        'jt_entry', BranchTableEntry, base_size=2,
+        ins=(GPR, GPR),
+        outs=(GPR),
+        clobbers_flags=False,
+        instp=valid_scale(BranchTableEntry),
+        compute_size="size_plus_maybe_offset_for_in_reg_1",
+        emit='''
+        PUT_OP(bits, rex3(in_reg1, out_reg0, in_reg0), sink);
+        if needs_offset(in_reg1) {
+            modrm_sib_disp8(out_reg0, sink);
+            sib(imm.trailing_zeros() as u8, in_reg0, in_reg1, sink);
+            sink.put1(0);
+        } else {
+            modrm_sib(out_reg0, sink);
+            sib(imm.trailing_zeros() as u8, in_reg0, in_reg1, sink);
+        }
+        ''')
+
+jt_base = TailRecipe(
+        'jt_base', BranchTableBase, base_size=5, ins=(), outs=(GPR),
+        clobbers_flags=False,
+        emit='''
+        PUT_OP(bits, rex2(0, out_reg0), sink);
+        modrm_riprel(out_reg0, sink);
+
+        // No reloc is needed here as the jump table is emitted directly after
+        // the function body.
+        jt_disp4(table, func, sink);
+        ''')
+
 #
 # Test flags and set a register.
 #
 # These setCC instructions only set the low 8 bits, and they can only write
 # ABCD registers without a REX prefix.
 #
 # Other instruction encodings accepting `b1` inputs have the same constraints
 # and only look at the low 8 bits of the input register.
 #
 
 seti = TailRecipe(
-        'seti', IntCond, size=1, ins=FLAG.rflags, outs=GPR,
+        'seti', IntCond, base_size=1, ins=FLAG.rflags, outs=GPR,
         requires_prefix=True,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink);
         modrm_r_bits(out_reg0, bits, sink);
         ''')
 seti_abcd = TailRecipe(
-        'seti_abcd', IntCond, size=1, ins=FLAG.rflags, outs=ABCD,
+        'seti_abcd', IntCond, base_size=1, ins=FLAG.rflags, outs=ABCD,
         when_prefixed=seti,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink);
         modrm_r_bits(out_reg0, bits, sink);
         ''')
 
 setf = TailRecipe(
-        'setf', FloatCond, size=1, ins=FLAG.rflags, outs=GPR,
+        'setf', FloatCond, base_size=1, ins=FLAG.rflags, outs=GPR,
         requires_prefix=True,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink);
         modrm_r_bits(out_reg0, bits, sink);
         ''')
 setf_abcd = TailRecipe(
-        'setf_abcd', FloatCond, size=1, ins=FLAG.rflags, outs=ABCD,
+        'setf_abcd', FloatCond, base_size=1, ins=FLAG.rflags, outs=ABCD,
         when_prefixed=setf,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink);
         modrm_r_bits(out_reg0, bits, sink);
         ''')
 
 #
 # Conditional move (a.k.a integer select)
 # (maybe-REX.W) 0F 4x modrm(r,r)
 # 1 byte, modrm(r,r), is after the opcode
 #
 cmov = TailRecipe(
-        'cmov', IntSelect, size=1, ins=(FLAG.rflags, GPR, GPR), outs=2,
+        'cmov', IntSelect, base_size=1, ins=(FLAG.rflags, GPR, GPR), outs=2,
         requires_prefix=False,
         clobbers_flags=False,
         emit='''
         PUT_OP(bits | icc2opc(cond), rex2(in_reg1, in_reg2), sink);
         modrm_rr(in_reg1, in_reg2, sink);
         ''')
 
 #
 # Bit scan forwards and reverse
 #
 bsf_and_bsr = TailRecipe(
-        'bsf_and_bsr', Unary, size=1, ins=GPR, outs=(GPR, FLAG.rflags),
+        'bsf_and_bsr', Unary, base_size=1, ins=GPR, outs=(GPR, FLAG.rflags),
         requires_prefix=False,
         clobbers_flags=True,
         emit='''
         PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
         modrm_rr(in_reg0, out_reg0, sink);
         ''')
 
 #
 # Compare and set flags.
 #
 
 # XX /r, MR form. Compare two GPR registers and set flags.
 rcmp = TailRecipe(
-        'rcmp', Binary, size=1, ins=(GPR, GPR), outs=FLAG.rflags,
+        'rcmp', Binary, base_size=1, ins=(GPR, GPR), outs=FLAG.rflags,
         emit='''
         PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
         modrm_rr(in_reg0, in_reg1, sink);
         ''')
 
 # XX /r, RM form. Compare two FPR registers and set flags.
 fcmp = TailRecipe(
-        'fcmp', Binary, size=1, ins=(FPR, FPR), outs=FLAG.rflags,
+        'fcmp', Binary, base_size=1, ins=(FPR, FPR), outs=FLAG.rflags,
         emit='''
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_rr(in_reg1, in_reg0, sink);
         ''')
 
 # XX /n, MI form with imm8.
 rcmp_ib = TailRecipe(
-        'rcmp_ib', BinaryImm, size=2, ins=GPR, outs=FLAG.rflags,
+        'rcmp_ib', BinaryImm, base_size=2, ins=GPR, outs=FLAG.rflags,
         instp=IsSignedInt(BinaryImm.imm, 8),
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         let imm: i64 = imm.into();
         sink.put1(imm as u8);
         ''')
 
 # XX /n, MI form with imm32.
 rcmp_id = TailRecipe(
-        'rcmp_id', BinaryImm, size=5, ins=GPR, outs=FLAG.rflags,
+        'rcmp_id', BinaryImm, base_size=5, ins=GPR, outs=FLAG.rflags,
         instp=IsSignedInt(BinaryImm.imm, 32),
         emit='''
         PUT_OP(bits, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         let imm: i64 = imm.into();
         sink.put4(imm as u32);
         ''')
 
 # Same as rcmp, but second operand is the stack pointer.
 rcmp_sp = TailRecipe(
-        'rcmp_sp', Unary, size=1, ins=GPR, outs=FLAG.rflags,
+        'rcmp_sp', Unary, base_size=1, ins=GPR, outs=FLAG.rflags,
         emit='''
         PUT_OP(bits, rex2(in_reg0, RU::rsp.into()), sink);
         modrm_rr(in_reg0, RU::rsp.into(), sink);
         ''')
 
 # Test-and-branch.
 #
 # This recipe represents the macro fusion of a test and a conditional branch.
@@ -1602,84 +1763,84 @@ rcmp_sp = TailRecipe(
 #    macro fusion is guaranteed to be possible.
 # 2. Hide the status flags from Cranelift which doesn't currently model flags.
 #
 # The encoding bits affect both the test and the branch instruction:
 #
 # Bits 0-7 are the Jcc opcode.
 # Bits 8-15 control the test instruction which always has opcode byte 0x85.
 tjccb = TailRecipe(
-        'tjccb', Branch, size=1 + 2, ins=GPR, outs=(),
+        'tjccb', Branch, base_size=1 + 2, ins=GPR, outs=(),
         branch_range=8,
         emit='''
         // test r, r.
         PUT_OP((bits & 0xff00) | 0x85, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(bits as u8);
         disp1(destination, func, sink);
         ''')
 
 tjccd = TailRecipe(
-        'tjccd', Branch, size=1 + 6, ins=GPR, outs=(),
+        'tjccd', Branch, base_size=1 + 6, ins=GPR, outs=(),
         branch_range=32,
         emit='''
         // test r, r.
         PUT_OP((bits & 0xff00) | 0x85, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(0x0f);
         sink.put1(bits as u8);
         disp4(destination, func, sink);
         ''')
 
 # 8-bit test-and-branch.
 #
 # Same as tjccb, but only looks at the low 8 bits of the register, for b1
 # types.
 t8jccb = TailRecipe(
-        't8jccb', Branch, size=1 + 2, ins=GPR, outs=(),
+        't8jccb', Branch, base_size=1 + 2, ins=GPR, outs=(),
         branch_range=8,
         requires_prefix=True,
         emit='''
         // test8 r, r.
         PUT_OP((bits & 0xff00) | 0x84, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(bits as u8);
         disp1(destination, func, sink);
         ''')
 t8jccb_abcd = TailRecipe(
-        't8jccb_abcd', Branch, size=1 + 2, ins=ABCD, outs=(),
+        't8jccb_abcd', Branch, base_size=1 + 2, ins=ABCD, outs=(),
         branch_range=8,
         when_prefixed=t8jccb,
         emit='''
         // test8 r, r.
         PUT_OP((bits & 0xff00) | 0x84, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(bits as u8);
         disp1(destination, func, sink);
         ''')
 
 t8jccd = TailRecipe(
-        't8jccd', Branch, size=1 + 6, ins=GPR, outs=(),
+        't8jccd', Branch, base_size=1 + 6, ins=GPR, outs=(),
         branch_range=32,
         requires_prefix=True,
         emit='''
         // test8 r, r.
         PUT_OP((bits & 0xff00) | 0x84, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(0x0f);
         sink.put1(bits as u8);
         disp4(destination, func, sink);
         ''')
 t8jccd_abcd = TailRecipe(
-        't8jccd_abcd', Branch, size=1 + 6, ins=ABCD, outs=(),
+        't8jccd_abcd', Branch, base_size=1 + 6, ins=ABCD, outs=(),
         branch_range=32,
         when_prefixed=t8jccd,
         emit='''
         // test8 r, r.
         PUT_OP((bits & 0xff00) | 0x84, rex2(in_reg0, in_reg0), sink);
         modrm_rr(in_reg0, in_reg0, sink);
         // Jcc instruction.
         sink.put1(0x0f);
@@ -1688,17 +1849,17 @@ t8jccd_abcd = TailRecipe(
         ''')
 
 # Worst case test-and-branch recipe for brz.b1 and brnz.b1 in 32-bit mode.
 # The register allocator can't handle a branch instruction with constrained
 # operands like the t8jccd_abcd above. This variant can accept the b1 opernd in
 # any register, but is is larger because it uses a 32-bit test instruction with
 # a 0xff immediate.
 t8jccd_long = TailRecipe(
-        't8jccd_long', Branch, size=5 + 6, ins=GPR, outs=(),
+        't8jccd_long', Branch, base_size=5 + 6, ins=GPR, outs=(),
         branch_range=32,
         emit='''
         // test32 r, 0xff.
         PUT_OP((bits & 0xff00) | 0xf7, rex1(in_reg0), sink);
         modrm_r_bits(in_reg0, bits, sink);
         sink.put4(0xff);
         // Jcc instruction.
         sink.put1(0x0f);
@@ -1719,17 +1880,17 @@ t8jccd_long = TailRecipe(
 # Since the `setCC` instructions only write an 8-bit register, we use that as
 # our `b1` representation: A `b1` value is represented as a GPR where the low 8
 # bits are known to be 0 or 1. The high bits are undefined.
 #
 # This bandaid macro doesn't support a REX prefix for the final `setCC`
 # instruction, so it is limited to the `ABCD` register class for booleans.
 # The omission of a `when_prefixed` alternative is deliberate here.
 icscc = TailRecipe(
-        'icscc', IntCompare, size=1 + 3, ins=(GPR, GPR), outs=ABCD,
+        'icscc', IntCompare, base_size=1 + 3, ins=(GPR, GPR), outs=ABCD,
         emit='''
         // Comparison instruction.
         PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
         modrm_rr(in_reg0, in_reg1, sink);
         // `setCC` instruction, no REX.
         use ir::condcodes::IntCC::*;
         let setcc = match cond {
             Equal => 0x94,
@@ -1744,17 +1905,17 @@ icscc = TailRecipe(
             UnsignedLessThanOrEqual => 0x96,
         };
         sink.put1(0x0f);
         sink.put1(setcc);
         modrm_rr(out_reg0, 0, sink);
         ''')
 
 icscc_ib = TailRecipe(
-        'icscc_ib', IntCompareImm, size=2 + 3, ins=GPR, outs=ABCD,
+        'icscc_ib', IntCompareImm, base_size=2 + 3, ins=GPR, outs=ABCD,
         instp=IsSignedInt(IntCompareImm.imm, 8),
         emit='''
         // 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.
@@ -1772,17 +1933,17 @@ icscc_ib = TailRecipe(
             UnsignedLessThanOrEqual => 0x96,
         };
         sink.put1(0x0f);
         sink.put1(setcc);
         modrm_rr(out_reg0, 0, sink);
         ''')
 
 icscc_id = TailRecipe(
-        'icscc_id', IntCompareImm, size=5 + 3, ins=GPR, outs=ABCD,
+        'icscc_id', IntCompareImm, base_size=5 + 3, ins=GPR, outs=ABCD,
         instp=IsSignedInt(IntCompareImm.imm, 32),
         emit='''
         // 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.
@@ -1814,17 +1975,17 @@ icscc_id = TailRecipe(
 # UN 111 000
 # GT 000 000
 # LT 001 000
 # EQ 100 000
 #
 # Not all floating point condition codes are supported.
 # The omission of a `when_prefixed` alternative is deliberate here.
 fcscc = TailRecipe(
-        'fcscc', FloatCompare, size=1 + 3, ins=(FPR, FPR), outs=ABCD,
+        'fcscc', FloatCompare, base_size=1 + 3, ins=(FPR, FPR), outs=ABCD,
         instp=floatccs(FloatCompare),
         emit='''
         // Comparison instruction.
         PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
         modrm_rr(in_reg1, in_reg0, sink);
         // `setCC` instruction, no REX.
         use ir::condcodes::FloatCC::*;
         let setcc = match cond {
--- a/third_party/rust/cranelift-codegen/meta-python/isa/x86/registers.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/x86/registers.py
@@ -41,24 +41,17 @@ FloatRegs = RegBank(
 FlagRegs = RegBank(
         'FlagRegs', ISA,
         'Flag registers',
         units=1,
         pressure_tracking=False,
         names=['rflags'])
 
 GPR = RegClass(IntRegs)
-# Certain types of deref encodings cannot be used with all registers.
-#   R13/RBP cannot be used with zero-offset load or store instructions.
-#   R12 cannot be used with a non-SIB-byte encoding of all derefs.
-GPR_DEREF_SAFE = GPR.without(GPR.rsp, GPR.r12)
-GPR_ZERO_DEREF_SAFE = GPR_DEREF_SAFE.without(GPR.rbp, GPR.r13)
 GPR8 = GPR[0:8]
-GPR8_DEREF_SAFE = GPR8.without(GPR.rsp)
-GPR8_ZERO_DEREF_SAFE = GPR8_DEREF_SAFE.without(GPR.rbp)
 ABCD = GPR[0:4]
 FPR = RegClass(FloatRegs)
 FPR8 = FPR[0:8]
 FLAG = RegClass(FlagRegs)
 
 # Constraints for stack operands.
 
 # Stack operand with a 32-bit signed displacement from either RBP or RSP.
--- a/third_party/rust/cranelift-codegen/meta-python/semantics/__init__.py
+++ b/third_party/rust/cranelift-codegen/meta-python/semantics/__init__.py
@@ -14,21 +14,21 @@ except ImportError:
 
 
 def verify_semantics(inst, src, xforms):
     # type: (Instruction, Rtl, InstructionSemantics) -> None
     """
     Verify that the semantics transforms in xforms correctly describe the
     instruction described by the src Rtl. This involves checking that:
         0) src is a single instance of inst
-        1) For all x\in xforms x.src is a single instance of inst
+        1) For all x \\in xforms x.src is a single instance of inst
         2) For any concrete values V of Literals in inst:
             For all concrete typing T of inst:
-                Exists single x \in xforms that applies to src conretazied to V
-                and T
+                Exists single x \\in xforms that applies to src conretazied to
+                V and T
     """
     # 0) The source rtl is always a single instance of inst
     assert len(src.rtl) == 1 and src.rtl[0].expr.inst == inst
 
     # 1) For all XForms x, x.src is a single instance of inst
     for x in xforms:
         assert len(x.src.rtl) == 1 and x.src.rtl[0].expr.inst == inst
 
--- a/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
@@ -27,33 +27,32 @@ use std::ptr::write_unaligned;
 ///
 /// Any relocations in the function are forwarded to the `RelocSink` trait object.
 ///
 /// Note that `MemoryCodeSink` writes multi-byte values in the native byte order of the host. This
 /// is not the right thing to do for cross compilation.
 pub struct MemoryCodeSink<'a> {
     data: *mut u8,
     offset: isize,
+    /// Size of the machine code portion of output
+    pub code_size: isize,
     relocs: &'a mut RelocSink,
     traps: &'a mut TrapSink,
 }
 
 impl<'a> MemoryCodeSink<'a> {
     /// Create a new memory code sink that writes a function to the memory pointed to by `data`.
     ///
     /// This function is unsafe since `MemoryCodeSink` does not perform bounds checking on the
     /// memory buffer, and it can't guarantee that the `data` pointer is valid.
-    pub unsafe fn new<'sink>(
-        data: *mut u8,
-        relocs: &'sink mut RelocSink,
-        traps: &'sink mut TrapSink,
-    ) -> MemoryCodeSink<'sink> {
-        MemoryCodeSink {
+    pub unsafe fn new(data: *mut u8, relocs: &'a mut RelocSink, traps: &'a mut TrapSink) -> Self {
+        Self {
             data,
             offset: 0,
+            code_size: 0,
             relocs,
             traps,
         }
     }
 }
 
 /// A trait for receiving relocations for code that is emitted directly into memory.
 pub trait RelocSink {
@@ -126,16 +125,20 @@ impl<'a> CodeSink for MemoryCodeSink<'a>
         let ofs = self.offset();
         self.relocs.reloc_jt(ofs, rel, jt);
     }
 
     fn trap(&mut self, code: TrapCode, srcloc: SourceLoc) {
         let ofs = self.offset();
         self.traps.trap(ofs, srcloc, code);
     }
+
+    fn begin_rodata(&mut self) {
+        self.code_size = self.offset;
+    }
 }
 
 /// A `TrapSink` implementation that does nothing, which is convenient when
 /// compiling code that does not rely on trapping semantics.
 pub struct NullTrapSink {}
 
 impl TrapSink for NullTrapSink {
     fn trap(&mut self, _offset: CodeOffset, _srcloc: SourceLoc, _code: TrapCode) {}
--- a/third_party/rust/cranelift-codegen/src/binemit/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/mod.rs
@@ -89,16 +89,19 @@ pub trait CodeSink {
     /// Add a relocation referencing an external symbol plus the addend at the current offset.
     fn reloc_external(&mut self, Reloc, &ExternalName, Addend);
 
     /// Add a relocation referencing a jump table.
     fn reloc_jt(&mut self, Reloc, JumpTable);
 
     /// Add trap information for the current offset.
     fn trap(&mut self, TrapCode, SourceLoc);
+
+    /// Code output is complete, read-only data may follow.
+    fn begin_rodata(&mut self);
 }
 
 /// Report a bad encoding error.
 #[cold]
 pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
     panic!(
         "Bad encoding {} for {}",
         func.encodings[inst],
@@ -118,9 +121,20 @@ where
     let mut divert = RegDiversions::new();
     for ebb in func.layout.ebbs() {
         divert.clear();
         debug_assert_eq!(func.offsets[ebb], sink.offset());
         for inst in func.layout.ebb_insts(ebb) {
             emit_inst(func, inst, &mut divert, sink);
         }
     }
+
+    sink.begin_rodata();
+
+    // output jump tables
+    for (jt, jt_data) in func.jump_tables.iter() {
+        let jt_offset = func.jt_offsets[jt];
+        for ebb in jt_data.iter() {
+            let rel_offset: i32 = func.offsets[*ebb] as i32 - jt_offset as i32;
+            sink.put4(rel_offset as u32)
+        }
+    }
 }
--- a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
@@ -27,16 +27,17 @@
 //! ebb23:
 //! ```
 
 use binemit::CodeOffset;
 use cursor::{Cursor, FuncCursor};
 use ir::{Function, InstructionData, Opcode};
 use isa::{EncInfo, TargetIsa};
 use iterators::IteratorExtras;
+use regalloc::RegDiversions;
 use timing;
 use CodegenResult;
 
 /// Relax branches and compute the final layout of EBB headers in `func`.
 ///
 /// Fill in the `func.offsets` table so the function is ready for binary emission.
 pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<CodeOffset> {
     let _tt = timing::relax_branches();
@@ -46,60 +47,72 @@ pub fn relax_branches(func: &mut Functio
     // Clear all offsets so we can recognize EBBs that haven't been visited yet.
     func.offsets.clear();
     func.offsets.resize(func.dfg.num_ebbs());
 
     // Start by inserting fall through instructions.
     fallthroughs(func);
 
     let mut offset = 0;
+    let mut divert = RegDiversions::new();
 
     // The relaxation algorithm iterates to convergence.
     let mut go_again = true;
     while go_again {
         go_again = false;
         offset = 0;
 
         // Visit all instructions in layout order
         let mut cur = FuncCursor::new(func);
         while let Some(ebb) = cur.next_ebb() {
+            divert.clear();
+
             // Record the offset for `ebb` and make sure we iterate until offsets are stable.
             if cur.func.offsets[ebb] != offset {
                 debug_assert!(
                     cur.func.offsets[ebb] < offset,
                     "Code shrinking during relaxation"
                 );
                 cur.func.offsets[ebb] = offset;
                 go_again = true;
             }
 
             while let Some(inst) = cur.next_inst() {
+                divert.apply(&cur.func.dfg[inst]);
+
                 let enc = cur.func.encodings[inst];
-                let size = encinfo.bytes(enc);
 
                 // See if this might be a branch that is out of range.
                 if let Some(range) = encinfo.branch_range(enc) {
                     if let Some(dest) = cur.func.dfg[inst].branch_destination() {
                         let dest_offset = cur.func.offsets[dest];
                         // This could be an out-of-range branch.
                         // Relax it unless the destination offset has not been computed yet.
                         if !range.contains(offset, dest_offset)
                             && (dest_offset != 0 || Some(dest) == cur.func.layout.entry_block())
                         {
-                            offset += relax_branch(&mut cur, offset, dest_offset, &encinfo, isa);
+                            offset +=
+                                relax_branch(&mut cur, &divert, offset, dest_offset, &encinfo, isa);
                             continue;
                         }
                     }
                 }
 
-                offset += size;
+                offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
             }
         }
     }
 
+    for (jt, jt_data) in func.jump_tables.iter() {
+        func.jt_offsets[jt] = offset;
+        // TODO: this should be computed based on the min size needed to hold
+        //        the furthest branch.
+        offset += jt_data.len() as u32 * 4;
+    }
+
     Ok(offset)
 }
 
 /// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any
 /// existing `fallthrough` instructions are correct.
 fn fallthroughs(func: &mut Function) {
     for (ebb, succ) in func.layout.ebbs().adjacent_pairs() {
         let term = func.layout.last_inst(ebb).expect("EBB has no terminator.");
@@ -129,16 +142,17 @@ fn fallthroughs(func: &mut Function) {
 }
 
 /// Relax the branch instruction at `cur` so it can cover the range `offset - dest_offset`.
 ///
 /// Return the size of the replacement instructions up to and including the location where `cur` is
 /// left.
 fn relax_branch(
     cur: &mut FuncCursor,
+    divert: &RegDiversions,
     offset: CodeOffset,
     dest_offset: CodeOffset,
     encinfo: &EncInfo,
     isa: &TargetIsa,
 ) -> CodeOffset {
     let inst = cur.current_inst().unwrap();
     debug!(
         "Relaxing [{}] {} for {:#x}-{:#x} range",
@@ -169,17 +183,17 @@ fn relax_branch(
                 debug!("  trying [{}]: constraints differ", encinfo.display(enc));
                 false
             } else {
                 debug!("  trying [{}]: OK", encinfo.display(enc));
                 true
             }
         }) {
         cur.func.encodings[inst] = enc;
-        return encinfo.bytes(enc);
+        return encinfo.byte_size(enc, inst, &divert, &cur.func);
     }
 
     // Note: On some RISC ISAs, conditional branches have shorter range than unconditional
     // branches, so one way of extending the range of a conditional branch is to invert its
     // condition and make it branch over an unconditional jump which has the larger range.
     //
     // Splitting the EBB is problematic this late because there may be register diversions in
     // effect across the conditional branch, and they can't survive the control flow edge to a new
--- a/third_party/rust/cranelift-codegen/src/binemit/shrink.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/shrink.rs
@@ -43,27 +43,27 @@ pub fn shrink_instructions(func: &mut Fu
                 }
 
                 let ctrl_type = func.dfg.ctrl_typevar(inst);
 
                 // Pick the last encoding with constraints that are satisfied.
                 let best_enc = isa
                     .legal_encodings(func, &func.dfg[inst], ctrl_type)
                     .filter(|e| encinfo.constraints[e.recipe()].satisfied(inst, &divert, &func))
-                    .min_by_key(|e| encinfo.bytes(*e))
+                    .min_by_key(|e| encinfo.byte_size(*e, inst, &divert, &func))
                     .unwrap();
 
                 if best_enc != enc {
                     func.encodings[inst] = best_enc;
 
                     debug!(
                         "Shrunk [{}] to [{}] in {}, reducing the size from {} to {}",
                         encinfo.display(enc),
                         encinfo.display(best_enc),
                         func.dfg.display_inst(inst, isa),
-                        encinfo.bytes(enc),
-                        encinfo.bytes(best_enc)
+                        encinfo.byte_size(enc, inst, &divert, &func),
+                        encinfo.byte_size(best_enc, inst, &divert, &func)
                     );
                 }
             }
         }
     }
 }
--- a/third_party/rust/cranelift-codegen/src/cfg_printer.rs
+++ b/third_party/rust/cranelift-codegen/src/cfg_printer.rs
@@ -10,18 +10,18 @@ use ir::Function;
 pub struct CFGPrinter<'a> {
     func: &'a Function,
     cfg: ControlFlowGraph,
 }
 
 /// A utility for pretty-printing the CFG of a `Function`.
 impl<'a> CFGPrinter<'a> {
     /// Create a new CFGPrinter.
-    pub fn new(func: &'a Function) -> CFGPrinter<'a> {
-        CFGPrinter {
+    pub fn new(func: &'a Function) -> Self {
+        Self {
             func,
             cfg: ControlFlowGraph::with_function(func),
         }
     }
 
     /// Write the CFG for this function to `w`.
     pub fn write(&self, w: &mut Write) -> Result {
         self.header(w)?;
@@ -43,18 +43,21 @@ impl<'a> CFGPrinter<'a> {
             write!(w, "    {} [shape=record, label=\"{{{}", ebb, ebb)?;
             // Add all outgoing branch instructions to the label.
             for inst in self.func.layout.ebb_insts(ebb) {
                 let idata = &self.func.dfg[inst];
                 match idata.analyze_branch(&self.func.dfg.value_lists) {
                     BranchInfo::SingleDest(dest, _) => {
                         write!(w, " | <{}>{} {}", inst, idata.opcode(), dest)?
                     }
-                    BranchInfo::Table(table) => {
-                        write!(w, " | <{}>{} {}", inst, idata.opcode(), table)?
+                    BranchInfo::Table(table, dest) => {
+                        write!(w, " | <{}>{} {}", inst, idata.opcode(), table)?;
+                        if let Some(dest) = dest {
+                            write!(w, " {}", dest)?
+                        }
                     }
                     BranchInfo::NotABranch => {}
                 }
             }
             writeln!(w, "}}\"]")?
         }
         Ok(())
     }
--- a/third_party/rust/cranelift-codegen/src/context.rs
+++ b/third_party/rust/cranelift-codegen/src/context.rs
@@ -17,21 +17,21 @@ use dominator_tree::DominatorTree;
 use flowgraph::ControlFlowGraph;
 use ir::Function;
 use isa::TargetIsa;
 use legalize_function;
 use licm::do_licm;
 use loop_analysis::LoopAnalysis;
 use nan_canonicalization::do_nan_canonicalization;
 use postopt::do_postopt;
-use preopt::do_preopt;
 use regalloc;
 use result::CodegenResult;
 use settings::{FlagsOrIsa, OptLevel};
 use simple_gvn::do_simple_gvn;
+use simple_preopt::do_preopt;
 use std::vec::Vec;
 use timing;
 use unreachable_code::eliminate_unreachable_code;
 use verifier::{verify_context, verify_locations, VerifierErrors, VerifierResult};
 
 /// Persistent data structures and compilation pipeline.
 pub struct Context {
     /// The function we're compiling.
@@ -96,24 +96,17 @@ impl Context {
         isa: &TargetIsa,
         mem: &mut Vec<u8>,
         relocs: &mut RelocSink,
         traps: &mut TrapSink,
     ) -> CodegenResult<()> {
         let code_size = self.compile(isa)?;
         let old_len = mem.len();
         mem.resize(old_len + code_size as usize, 0);
-        unsafe {
-            self.emit_to_memory(
-                isa,
-                mem.as_mut_ptr().offset(old_len as isize),
-                relocs,
-                traps,
-            )
-        };
+        unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
         Ok(())
     }
 
     /// Compile the function.
     ///
     /// Run the function through all the passes necessary to generate code for the target ISA
     /// represented by `isa`. This does not include the final step of emitting machine code into a
     /// code sink.
@@ -323,12 +316,11 @@ impl Context {
         Ok(())
     }
 
     /// Run the branch relaxation pass and return the final code size.
     pub fn relax_branches(&mut self, isa: &TargetIsa) -> CodegenResult<CodeOffset> {
         let code_size = relax_branches(&mut self.func, isa)?;
         self.verify_if(isa)?;
         self.verify_locations_if(isa)?;
-
         Ok(code_size)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/cursor.rs
+++ b/third_party/rust/cranelift-codegen/src/cursor.rs
@@ -575,18 +575,18 @@ pub struct FuncCursor<'f> {
     srcloc: ir::SourceLoc,
 
     /// The referenced function.
     pub func: &'f mut ir::Function,
 }
 
 impl<'f> FuncCursor<'f> {
     /// Create a new `FuncCursor` pointing nowhere.
-    pub fn new(func: &'f mut ir::Function) -> FuncCursor<'f> {
-        FuncCursor {
+    pub fn new(func: &'f mut ir::Function) -> Self {
+        Self {
             pos: CursorPosition::Nowhere,
             srcloc: Default::default(),
             func,
         }
     }
 
     /// Use the source location of `inst` for future instructions.
     pub fn use_srcloc(&mut self, inst: ir::Inst) {
@@ -657,18 +657,18 @@ pub struct EncCursor<'f> {
     pub func: &'f mut ir::Function,
 
     /// The target ISA that will be used to encode instructions.
     pub isa: &'f TargetIsa,
 }
 
 impl<'f> EncCursor<'f> {
     /// Create a new `EncCursor` pointing nowhere.
-    pub fn new(func: &'f mut ir::Function, isa: &'f TargetIsa) -> EncCursor<'f> {
-        EncCursor {
+    pub fn new(func: &'f mut ir::Function, isa: &'f TargetIsa) -> Self {
+        Self {
             pos: CursorPosition::Nowhere,
             srcloc: Default::default(),
             built_inst: None,
             func,
             isa,
         }
     }
 
--- a/third_party/rust/cranelift-codegen/src/dominator_tree.rs
+++ b/third_party/rust/cranelift-codegen/src/dominator_tree.rs
@@ -1,11 +1,11 @@
 //! A Dominator Tree represented as mappings of Ebbs to their immediate dominator.
 
-use entity::EntityMap;
+use entity::SecondaryMap;
 use flowgraph::{BasicBlock, ControlFlowGraph};
 use ir::instructions::BranchInfo;
 use ir::{Ebb, ExpandedProgramPoint, Function, Inst, Layout, ProgramOrder, Value};
 use packed_option::PackedOption;
 use std::cmp;
 use std::cmp::Ordering;
 use std::mem;
 use std::vec::Vec;
@@ -33,17 +33,17 @@ struct DomNode {
     ///
     /// This is `None` for unreachable blocks and the entry block which doesn't have an immediate
     /// dominator.
     idom: PackedOption<Inst>,
 }
 
 /// The dominator tree for a single function.
 pub struct DominatorTree {
-    nodes: EntityMap<Ebb, DomNode>,
+    nodes: SecondaryMap<Ebb, DomNode>,
 
     /// CFG post-order of all reachable EBBs.
     postorder: Vec<Ebb>,
 
     /// Scratch memory used by `compute_postorder()`.
     stack: Vec<Ebb>,
 
     valid: bool,
@@ -212,17 +212,17 @@ impl DominatorTree {
     }
 }
 
 impl DominatorTree {
     /// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a
     /// function.
     pub fn new() -> Self {
         Self {
-            nodes: EntityMap::new(),
+            nodes: SecondaryMap::new(),
             postorder: Vec::new(),
             stack: Vec::new(),
             valid: false,
         }
     }
 
     /// Allocate and compute a dominator tree.
     pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self {
@@ -340,35 +340,38 @@ impl DominatorTree {
     /// Push `ebb` successors onto `self.stack`, filtering out those that have already been seen.
     ///
     /// The successors are pushed in program order which is important to get a split-invariant
     /// post-order. Split-invariant means that if an EBB is split in two, we get the same
     /// post-order except for the insertion of the new EBB header at the split point.
     fn push_successors(&mut self, func: &Function, ebb: Ebb) {
         for inst in func.layout.ebb_insts(ebb) {
             match func.dfg.analyze_branch(inst) {
-                BranchInfo::SingleDest(succ, _) => {
-                    if self.nodes[succ].rpo_number == 0 {
-                        self.nodes[succ].rpo_number = SEEN;
-                        self.stack.push(succ);
+                BranchInfo::SingleDest(succ, _) => self.push_if_unseen(succ),
+                BranchInfo::Table(jt, dest) => {
+                    for succ in func.jump_tables[jt].iter() {
+                        self.push_if_unseen(*succ);
                     }
-                }
-                BranchInfo::Table(jt) => {
-                    for (_, succ) in func.jump_tables[jt].entries() {
-                        if self.nodes[succ].rpo_number == 0 {
-                            self.nodes[succ].rpo_number = SEEN;
-                            self.stack.push(succ);
-                        }
+                    if let Some(dest) = dest {
+                        self.push_if_unseen(dest);
                     }
                 }
                 BranchInfo::NotABranch => {}
             }
         }
     }
 
+    /// Push `ebb` onto `self.stack` if it has not already been seen.
+    fn push_if_unseen(&mut self, ebb: Ebb) {
+        if self.nodes[ebb].rpo_number == 0 {
+            self.nodes[ebb].rpo_number = SEEN;
+            self.stack.push(ebb);
+        }
+    }
+
     /// Build a dominator tree from a control flow graph using Keith D. Cooper's
     /// "Simple, Fast Dominator Algorithm."
     fn compute_domtree(&mut self, func: &Function, cfg: &ControlFlowGraph) {
         // During this algorithm, `rpo_number` has the following values:
         //
         // 0: EBB is not reachable.
         // 1: EBB is reachable, but has not yet been visited during the first pass. This is set by
         // `compute_postorder`.
@@ -500,17 +503,17 @@ impl DominatorTree {
 ///
 /// - A forward traversable dominator tree through the `children()` iterator.
 /// - An ordering of EBBs according to a dominator tree pre-order.
 /// - Constant time dominance checks at the EBB granularity.
 ///
 /// The information in this auxillary data structure is not easy to update when the control flow
 /// graph changes, which is why it is kept separate.
 pub struct DominatorTreePreorder {
-    nodes: EntityMap<Ebb, ExtraNode>,
+    nodes: SecondaryMap<Ebb, ExtraNode>,
 
     // Scratch memory used by `compute_postorder()`.
     stack: Vec<Ebb>,
 }
 
 #[derive(Default, Clone)]
 struct ExtraNode {
     /// First child node in the domtree.
@@ -528,17 +531,17 @@ struct ExtraNode {
     pre_max: u32,
 }
 
 /// Creating and computing the dominator tree pre-order.
 impl DominatorTreePreorder {
     /// Create a new blank `DominatorTreePreorder`.
     pub fn new() -> Self {
         Self {
-            nodes: EntityMap::new(),
+            nodes: SecondaryMap::new(),
             stack: Vec::new(),
         }
     }
 
     /// Recompute this data structure to match `domtree`.
     pub fn compute(&mut self, domtree: &DominatorTree, layout: &Layout) {
         self.nodes.clear();
         debug_assert_eq!(self.stack.len(), 0);
@@ -661,17 +664,17 @@ impl DominatorTreePreorder {
         let da = func.dfg.value_def(a);
         let db = func.dfg.value_def(b);
         self.pre_cmp(da, db, &func.layout)
             .then_with(|| da.num().cmp(&db.num()))
     }
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use cursor::{Cursor, FuncCursor};
     use flowgraph::ControlFlowGraph;
     use ir::types::*;
     use ir::{Function, InstBuilder, TrapCode};
     use settings;
     use verifier::{verify_context, VerifierErrors};
 
--- a/third_party/rust/cranelift-codegen/src/flowgraph.rs
+++ b/third_party/rust/cranelift-codegen/src/flowgraph.rs
@@ -19,17 +19,17 @@
 //!
 //!         jmp Ebb2     ; end of basic block
 //! ```
 //!
 //! Here `Ebb1` and `Ebb2` would each have a single predecessor denoted as `(Ebb0, brz)`
 //! and `(Ebb0, jmp Ebb2)` respectively.
 
 use bforest;
-use entity::EntityMap;
+use entity::SecondaryMap;
 use ir::instructions::BranchInfo;
 use ir::{Ebb, Function, Inst};
 use std::mem;
 use timing;
 
 /// A basic block denoted by its enclosing Ebb and last instruction.
 #[derive(PartialEq, Eq)]
 pub struct BasicBlock {
@@ -67,27 +67,27 @@ struct CFGNode {
     /// The set is ordered by EBB number, indicated by the `()` comparator type.
     pub successors: bforest::Set<Ebb>,
 }
 
 /// The Control Flow Graph maintains a mapping of ebbs to their predecessors
 /// and successors where predecessors are basic blocks and successors are
 /// extended basic blocks.
 pub struct ControlFlowGraph {
-    data: EntityMap<Ebb, CFGNode>,
+    data: SecondaryMap<Ebb, CFGNode>,
     pred_forest: bforest::MapForest<Inst, Ebb>,
     succ_forest: bforest::SetForest<Ebb>,
     valid: bool,
 }
 
 impl ControlFlowGraph {
     /// Allocate a new blank control flow graph.
     pub fn new() -> Self {
         Self {
-            data: EntityMap::new(),
+            data: SecondaryMap::new(),
             valid: false,
             pred_forest: bforest::MapForest::new(),
             succ_forest: bforest::SetForest::new(),
         }
     }
 
     /// Clear all data structures in this control flow graph.
     pub fn clear(&mut self) {
@@ -120,20 +120,23 @@ impl ControlFlowGraph {
     }
 
     fn compute_ebb(&mut self, func: &Function, ebb: Ebb) {
         for inst in func.layout.ebb_insts(ebb) {
             match func.dfg.analyze_branch(inst) {
                 BranchInfo::SingleDest(dest, _) => {
                     self.add_edge(ebb, inst, dest);
                 }
-                BranchInfo::Table(jt) => {
-                    for (_, dest) in func.jump_tables[jt].entries() {
+                BranchInfo::Table(jt, dest) => {
+                    if let Some(dest) = dest {
                         self.add_edge(ebb, inst, dest);
                     }
+                    for dest in func.jump_tables[jt].iter() {
+                        self.add_edge(ebb, inst, *dest);
+                    }
                 }
                 BranchInfo::NotABranch => {}
             }
         }
     }
 
     fn invalidate_ebb_successors(&mut self, ebb: Ebb) {
         // Temporarily take ownership because we need mutable access to self.data inside the loop.
--- a/third_party/rust/cranelift-codegen/src/ir/builder.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/builder.rs
@@ -23,17 +23,17 @@ pub trait InstBuilderBase<'f>: Sized {
     fn data_flow_graph(&self) -> &DataFlowGraph;
     /// Get a mutable reference to the data flow graph that will hold the constructed
     /// instructions.
     fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
 
     /// Insert an instruction and return a reference to it, consuming the builder.
     ///
     /// The result types may depend on a controlling type variable. For non-polymorphic
-    /// instructions with multiple results, pass `VOID` for the `ctrl_typevar` argument.
+    /// instructions with multiple results, pass `INVALID` for the `ctrl_typevar` argument.
     fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph);
 }
 
 // Include trait code generated by `lib/codegen/meta-python/gen_instr.py`.
 //
 // This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per
 // instruction format and per opcode.
 include!(concat!(env!("OUT_DIR"), "/inst_builder.rs"));
@@ -69,18 +69,18 @@ use std::marker::PhantomData;
 pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> {
     inserter: IIB,
     unused: PhantomData<&'f u32>,
 }
 
 impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> {
     /// Create a new builder which inserts instructions at `pos`.
     /// The `dfg` and `pos.layout` references should be from the same `Function`.
-    pub fn new(inserter: IIB) -> InsertBuilder<'f, IIB> {
-        InsertBuilder {
+    pub fn new(inserter: IIB) -> Self {
+        Self {
             inserter,
             unused: PhantomData,
         }
     }
 
     /// Reuse result values in `reuse`.
     ///
     /// Convert this builder into one that will reuse the provided result values instead of
@@ -180,18 +180,18 @@ where
 /// bug to leave result values dangling.
 pub struct ReplaceBuilder<'f> {
     dfg: &'f mut DataFlowGraph,
     inst: Inst,
 }
 
 impl<'f> ReplaceBuilder<'f> {
     /// Create a `ReplaceBuilder` that will overwrite `inst`.
-    pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> ReplaceBuilder {
-        ReplaceBuilder { dfg, inst }
+    pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self {
+        Self { dfg, inst }
     }
 }
 
 impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
     fn data_flow_graph(&self) -> &DataFlowGraph {
         self.dfg
     }
 
--- a/third_party/rust/cranelift-codegen/src/ir/dfg.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/dfg.rs
@@ -1,11 +1,11 @@
 //! Data flow graph tracking Instructions, Values, and EBBs.
 
-use entity::{EntityMap, PrimaryMap};
+use entity::{self, PrimaryMap, SecondaryMap};
 use ir;
 use ir::builder::ReplaceBuilder;
 use ir::extfunc::ExtFuncData;
 use ir::instructions::{BranchInfo, CallInfo, InstructionData};
 use ir::types;
 use ir::{Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueList, ValueListPool};
 use isa::TargetIsa;
 use packed_option::ReservedValue;
@@ -29,17 +29,17 @@ pub struct DataFlowGraph {
     /// The instructions in this map are not in program order. That is tracked by `Layout`, along
     /// with the EBB containing each instruction.
     insts: PrimaryMap<Inst, InstructionData>,
 
     /// List of result values for each instruction.
     ///
     /// This map gets resized automatically by `make_inst()` so it is always in sync with the
     /// primary `insts` map.
-    results: EntityMap<Inst, ValueList>,
+    results: SecondaryMap<Inst, ValueList>,
 
     /// Extended basic blocks in the function and their parameters.
     ///
     /// This map is not in program order. That is handled by `Layout`, and so is the sequence of
     /// instructions contained in each EBB.
     ebbs: PrimaryMap<Ebb, EbbData>,
 
     /// Memory pool of value lists.
@@ -62,17 +62,17 @@ pub struct DataFlowGraph {
     pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>,
 }
 
 impl DataFlowGraph {
     /// Create a new empty `DataFlowGraph`.
     pub fn new() -> Self {
         Self {
             insts: PrimaryMap::new(),
-            results: EntityMap::new(),
+            results: SecondaryMap::new(),
             ebbs: PrimaryMap::new(),
             value_lists: ValueListPool::new(),
             values: PrimaryMap::new(),
             signatures: PrimaryMap::new(),
             ext_funcs: PrimaryMap::new(),
         }
     }
 
@@ -85,30 +85,30 @@ impl DataFlowGraph {
         self.values.clear();
         self.signatures.clear();
         self.ext_funcs.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 `EntityMap::with_capacity`.
+    /// This is intended for use with `SecondaryMap::with_capacity`.
     pub fn num_insts(&self) -> usize {
         self.insts.len()
     }
 
     /// Returns `true` if the given instruction reference is valid.
     pub fn inst_is_valid(&self, inst: Inst) -> bool {
         self.insts.is_valid(inst)
     }
 
     /// Get the total number of extended basic blocks created in this function, whether they are
     /// currently inserted in the layout or not.
     ///
-    /// This is intended for use with `EntityMap::with_capacity`.
+    /// This is intended for use with `SecondaryMap::with_capacity`.
     pub fn num_ebbs(&self) -> usize {
         self.ebbs.len()
     }
 
     /// Returns `true` if the given ebb reference is valid.
     pub fn ebb_is_valid(&self, ebb: Ebb) -> bool {
         self.ebbs.is_valid(ebb)
     }
@@ -122,17 +122,17 @@ impl DataFlowGraph {
 /// Resolve value aliases.
 ///
 /// Find the original SSA value that `value` aliases, or None if an
 /// alias cycle is detected.
 fn maybe_resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Option<Value> {
     let mut v = value;
 
     // Note that values may be empty here.
-    for _ in 0..1 + values.len() {
+    for _ in 0..=values.len() {
         if let ValueData::Alias { original, .. } = values[v] {
             v = original;
         } else {
             return Some(v);
         }
     }
 
     None
@@ -144,25 +144,62 @@ fn maybe_resolve_aliases(values: &Primar
 fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value {
     if let Some(v) = maybe_resolve_aliases(values, value) {
         v
     } else {
         panic!("Value alias loop detected for {}", value);
     }
 }
 
+/// Iterator over all Values in a DFG
+pub struct Values<'a> {
+    inner: entity::Iter<'a, Value, ValueData>,
+}
+
+/// Check for non-values
+fn valid_valuedata(data: &ValueData) -> bool {
+    if let ValueData::Alias {
+        ty: types::INVALID,
+        original,
+    } = *data
+    {
+        if original == Value::reserved_value() {
+            return false;
+        }
+    }
+    true
+}
+
+impl<'a> Iterator for Values<'a> {
+    type Item = Value;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner
+            .by_ref()
+            .find(|kv| valid_valuedata(kv.1))
+            .map(|kv| kv.0)
+    }
+}
+
 /// Handling values.
 ///
 /// Values are either EBB parameters or instruction results.
 impl DataFlowGraph {
     /// Allocate an extended value entry.
     fn make_value(&mut self, data: ValueData) -> Value {
         self.values.push(data)
     }
 
+    /// Get an iterator over all values.
+    pub fn values<'a>(&'a self) -> Values {
+        Values {
+            inner: self.values.iter(),
+        }
+    }
+
     /// Check if a value reference is valid.
     pub fn value_is_valid(&self, v: Value) -> bool {
         self.values.is_valid(v)
     }
 
     /// Get the type of a value.
     pub fn value_type(&self, v: Value) -> Type {
         match self.values[v] {
@@ -244,17 +281,17 @@ impl DataFlowGraph {
             self.value_type(dest),
             ty,
             "Aliasing {} to {} would change its type {} to {}",
             dest,
             src,
             self.value_type(dest),
             ty
         );
-        debug_assert_ne!(ty, types::VOID);
+        debug_assert_ne!(ty, types::INVALID);
 
         self.values[dest] = ValueData::Alias { ty, original };
     }
 
     /// Replace the results of one instruction with aliases to the results of another.
     ///
     /// Change all the results of `dest_inst` to behave as aliases of
     /// corresponding results of `src_inst`, as if calling change_to_alias for
@@ -288,17 +325,17 @@ impl DataFlowGraph {
                 self.value_type(dest),
                 ty,
                 "Aliasing {} to {} would change its type {} to {}",
                 dest,
                 src,
                 self.value_type(dest),
                 ty
             );
-            debug_assert_ne!(ty, types::VOID);
+            debug_assert_ne!(ty, types::INVALID);
 
             self.values[dest] = ValueData::Alias { ty, original };
         }
 
         self.clear_results(dest_inst);
     }
 }
 
@@ -417,17 +454,17 @@ impl DataFlowGraph {
 
     /// Create result values for an instruction that produces multiple results.
     ///
     /// Instructions that produce no result values only need to be created with `make_inst`,
     /// otherwise call `make_inst_results` to allocate value table entries for the results.
     ///
     /// The result value types are determined from the instruction's value type constraints and the
     /// provided `ctrl_typevar` type for polymorphic instructions. For non-polymorphic
-    /// instructions, `ctrl_typevar` is ignored, and `VOID` can be used.
+    /// instructions, `ctrl_typevar` is ignored, and `INVALID` can be used.
     ///
     /// The type of the first result value is also set, even if it was already set in the
     /// `InstructionData` passed to `make_inst`. If this function is called with a single-result
     /// instruction, that is the only effect.
     pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize {
         self.make_inst_results_reusing(inst, ctrl_typevar, iter::empty())
     }
 
@@ -635,22 +672,22 @@ impl DataFlowGraph {
         self.call_signature(inst).and_then(|sigref| {
             self.signatures[sigref]
                 .returns
                 .get(result_idx - fixed_results)
                 .map(|&arg| arg.value_type)
         })
     }
 
-    /// Get the controlling type variable, or `VOID` if `inst` isn't polymorphic.
+    /// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic.
     pub fn ctrl_typevar(&self, inst: Inst) -> Type {
         let constraints = self[inst].opcode().constraints();
 
         if !constraints.is_polymorphic() {
-            types::VOID
+            types::INVALID
         } else if constraints.requires_typevar_operand() {
             // Not all instruction formats have a designated operand, but in that case
             // `requires_typevar_operand()` should never be true.
             self.value_type(
                 self[inst]
                     .typevar_operand(&self.value_lists)
                     .expect("Instruction format doesn't have a designated operand, bad opcode."),
             )
@@ -853,34 +890,34 @@ impl<'a> fmt::Display for DisplayInst<'a
             write!(f, "{}", first)?;
             for v in rest {
                 write!(f, ", {}", v)?;
             }
             write!(f, " = ")?;
         }
 
         let typevar = dfg.ctrl_typevar(inst);
-        if typevar.is_void() {
+        if typevar.is_invalid() {
             write!(f, "{}", dfg[inst].opcode())?;
         } else {
             write!(f, "{}.{}", dfg[inst].opcode(), typevar)?;
         }
         write_operands(f, dfg, isa, inst)
     }
 }
 
 /// Parser routines. These routines should not be used outside the parser.
 impl DataFlowGraph {
     /// Set the type of a value. This is only for use in the parser, which needs
     /// to create invalid values for index padding which may be reassigned later.
     #[cold]
     fn set_value_type_for_parser(&mut self, v: Value, t: Type) {
         assert_eq!(
             self.value_type(v),
-            types::VOID,
+            types::INVALID,
             "this function is only for assigning types to previously invalid values"
         );
         match self.values[v] {
             ValueData::Inst { ref mut ty, .. }
             | ValueData::Param { ref mut ty, .. }
             | ValueData::Alias { ref mut ty, .. } => *ty = t,
         }
     }
@@ -927,83 +964,83 @@ impl DataFlowGraph {
         self.values[val] = ValueData::Param {
             ty,
             num: num as u16,
             ebb,
         };
     }
 
     /// Create a new value alias. This is only for use by the parser to create
-    /// aliases with specific values.
+    /// aliases with specific values, and the printer for testing.
     #[cold]
-    pub fn make_value_alias_for_parser(&mut self, src: Value, dest: Value) {
+    pub fn make_value_alias_for_serialization(&mut self, src: Value, dest: Value) {
         assert_ne!(src, Value::reserved_value());
         assert_ne!(dest, Value::reserved_value());
 
         let ty = if self.values.is_valid(src) {
             self.value_type(src)
         } else {
-            // As a special case, if we can't resolve the aliasee yet, use VOID
+            // As a special case, if we can't resolve the aliasee yet, use INVALID
             // temporarily. It will be resolved later in parsing.
-            types::VOID
+            types::INVALID
         };
         let data = ValueData::Alias { ty, original: src };
         self.values[dest] = data;
     }
 
     /// If `v` is already defined as an alias, return its destination value.
     /// Otherwise return None. This allows the parser to coalesce identical
-    /// alias definitions.
+    /// alias definitions, and the printer to identify an alias's immediate target.
     #[cold]
-    pub fn value_alias_dest_for_parser(&self, v: Value) -> Option<Value> {
+    pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option<Value> {
         if let ValueData::Alias { original, .. } = self.values[v] {
             Some(original)
         } else {
             None
         }
     }
 
     /// Compute the type of an alias. This is only for use in the parser.
     /// Returns false if an alias cycle was encountered.
     #[cold]
     pub fn set_alias_type_for_parser(&mut self, v: Value) -> bool {
         if let Some(resolved) = maybe_resolve_aliases(&self.values, v) {
             let old_ty = self.value_type(v);
             let new_ty = self.value_type(resolved);
-            if old_ty == types::VOID {
+            if old_ty == types::INVALID {
                 self.set_value_type_for_parser(v, new_ty);
             } else {
                 assert_eq!(old_ty, new_ty);
             }
             true
         } else {
             false
         }
     }
 
     /// Create an invalid value, to pad the index space. This is only for use by
     /// the parser to pad out the value index space.
     #[cold]
     pub fn make_invalid_value_for_parser(&mut self) {
         let data = ValueData::Alias {
-            ty: types::VOID,
+            ty: types::INVALID,
             original: Value::reserved_value(),
         };
         self.make_value(data);
     }
 
     /// Check if a value reference is valid, while being aware of aliases which
     /// may be unresolved while parsing.
     #[cold]
     pub fn value_is_valid_for_parser(&self, v: Value) -> bool {
         if !self.value_is_valid(v) {
             return false;
         }
         if let ValueData::Alias { ty, .. } = self.values[v] {
-            ty != types::VOID
+            ty != types::INVALID
         } else {
             true
         }
     }
 }
 
 #[cfg(test)]
 mod tests {
--- a/third_party/rust/cranelift-codegen/src/ir/extfunc.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/extfunc.rs
@@ -1,18 +1,17 @@
 //! External function calls.
 //!
 //! To a Cranelift function, all functions are "external". Directly called functions must be
 //! declared in the preamble, and all function calls must have a signature.
 //!
 //! This module declares the data types used to represent external functions and call signatures.
 
 use ir::{ArgumentLoc, ExternalName, SigRef, Type};
-use isa::{RegInfo, RegUnit};
-use settings::CallConv;
+use isa::{CallConv, RegInfo, RegUnit};
 use std::fmt;
 use std::str::FromStr;
 use std::vec::Vec;
 
 /// Function signature.
 ///
 /// The function signature describes the types of formal parameters and return values along with
 /// other details that are needed to call a function correctly.
--- a/third_party/rust/cranelift-codegen/src/ir/function.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/function.rs
@@ -1,24 +1,25 @@
 //! Intermediate representation of a function.
 //!
 //! The `Function` struct defined in this module owns all of its extended basic blocks and
 //! instructions.
 
 use binemit::CodeOffset;
-use entity::{EntityMap, PrimaryMap};
+use entity::{PrimaryMap, SecondaryMap};
 use ir;
 use ir::{DataFlowGraph, ExternalName, Layout, Signature};
 use ir::{
     Ebb, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, JumpTable,
     JumpTableData, SigRef, StackSlot, StackSlotData, Table, TableData,
 };
-use ir::{EbbOffsets, InstEncodings, JumpTables, SourceLocs, StackSlots, ValueLocations};
-use isa::{EncInfo, Encoding, Legalize, TargetIsa};
-use settings::CallConv;
+use ir::{EbbOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations};
+use ir::{JumpTableOffsets, JumpTables};
+use isa::{CallConv, EncInfo, Encoding, Legalize, TargetIsa};
+use regalloc::RegDiversions;
 use std::fmt;
 use write::write_function;
 
 /// A function.
 ///
 /// Functions can be cloned, but it is not a very fast operation.
 /// The clone will have all the same entity numbers as the original.
 #[derive(Clone)]
@@ -59,16 +60,19 @@ pub struct Function {
 
     /// Code offsets of the EBB headers.
     ///
     /// This information is only transiently available after the `binemit::relax_branches` function
     /// computes it, and it can easily be recomputed by calling that function. It is not included
     /// in the textual IR format.
     pub offsets: EbbOffsets,
 
+    /// Code offsets of Jump Table headers.
+    pub jt_offsets: JumpTableOffsets,
+
     /// Source locations.
     ///
     /// Track the original source location for each instruction. The source locations are not
     /// interpreted by Cranelift, only preserved.
     pub srclocs: SourceLocs,
 }
 
 impl Function {
@@ -79,20 +83,21 @@ impl Function {
             signature: sig,
             stack_slots: StackSlots::new(),
             global_values: PrimaryMap::new(),
             heaps: PrimaryMap::new(),
             tables: PrimaryMap::new(),
             jump_tables: PrimaryMap::new(),
             dfg: DataFlowGraph::new(),
             layout: Layout::new(),
-            encodings: EntityMap::new(),
-            locations: EntityMap::new(),
-            offsets: EntityMap::new(),
-            srclocs: EntityMap::new(),
+            encodings: SecondaryMap::new(),
+            locations: SecondaryMap::new(),
+            offsets: SecondaryMap::new(),
+            jt_offsets: SecondaryMap::new(),
+            srclocs: SecondaryMap::new(),
         }
     }
 
     /// Clear all data structures in this function.
     pub fn clear(&mut self) {
         self.signature.clear(CallConv::Fast);
         self.stack_slots.clear();
         self.global_values.clear();
@@ -112,21 +117,16 @@ impl Function {
         Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast))
     }
 
     /// Creates a jump table in the function, to be used by `br_table` instructions.
     pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
         self.jump_tables.push(data)
     }
 
-    /// Inserts an entry in a previously declared jump table.
-    pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
-        self.jump_tables[jt].set_entry(index, ebb);
-    }
-
     /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
     /// `stack_addr` instructions.
     pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
         self.stack_slots.push(data)
     }
 
     /// Adds a signature which can later be used to declare an external function import.
     pub fn import_signature(&mut self, signature: Signature) -> SigRef {
@@ -179,16 +179,18 @@ impl Function {
     /// `binemit::relax_branches()` function.
     pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
         assert!(
             !self.offsets.is_empty(),
             "Code layout must be computed first"
         );
         InstOffsetIter {
             encinfo: encinfo.clone(),
+            func: self,
+            divert: RegDiversions::new(),
             encodings: &self.encodings,
             offset: self.offsets[ebb],
             iter: self.layout.ebb_insts(ebb),
         }
     }
 
     /// Wrapper around `encode` which assigns `inst` the resulting encoding.
     pub fn update_encoding(&mut self, inst: ir::Inst, isa: &TargetIsa) -> Result<(), Legalize> {
@@ -221,25 +223,30 @@ impl fmt::Debug for Function {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         write_function(fmt, self, None)
     }
 }
 
 /// Iterator returning instruction offsets and sizes: `(offset, inst, size)`.
 pub struct InstOffsetIter<'a> {
     encinfo: EncInfo,
+    divert: RegDiversions,
+    func: &'a Function,
     encodings: &'a InstEncodings,
     offset: CodeOffset,
     iter: ir::layout::Insts<'a>,
 }
 
 impl<'a> Iterator for InstOffsetIter<'a> {
     type Item = (CodeOffset, ir::Inst, CodeOffset);
 
     fn next(&mut self) -> Option<Self::Item> {
         self.iter.next().map(|inst| {
-            let size = self.encinfo.bytes(self.encodings[inst]);
+            self.divert.apply(&self.func.dfg[inst]);
+            let byte_size =
+                self.encinfo
+                    .byte_size(self.encodings[inst], inst, &self.divert, self.func);
             let offset = self.offset;
-            self.offset += size;
-            (offset, inst, size)
+            self.offset += byte_size;
+            (offset, inst, byte_size)
         })
     }
 }
--- a/third_party/rust/cranelift-codegen/src/ir/globalvalue.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/globalvalue.rs
@@ -1,85 +1,131 @@
 //! Global values.
 
-use ir::immediates::Offset32;
+use ir::immediates::{Imm64, Offset32};
 use ir::{ExternalName, GlobalValue, Type};
 use isa::TargetIsa;
 use std::fmt;
 
 /// Information about a global value declaration.
 #[derive(Clone)]
 pub enum GlobalValueData {
-    /// Value is the address of a field in the VM context struct, a constant offset from the VM
-    /// context pointer.
-    VMContext {
-        /// Offset from the `vmctx` pointer.
-        offset: Offset32,
-    },
+    /// Value is the address of the VM context struct.
+    VMContext,
 
     /// Value is pointed to by another global value.
     ///
     /// The `base` global value is assumed to contain a pointer. This global value is computed
-    /// by loading from memory at that pointer value, and then adding an offset. The memory must
-    /// be accessible, and naturally aligned to hold a value of the type.
-    Deref {
+    /// by loading from memory at that pointer value. The memory must be accessible, and
+    /// naturally aligned to hold a value of the type. The data at this address is assumed
+    /// to never change while the current function is executing.
+    Load {
+        /// The base pointer global value.
+        base: GlobalValue,
+
+        /// Offset added to the base pointer before doing the load.
+        offset: Offset32,
+
+        /// Type of the loaded value.
+        global_type: Type,
+
+        /// Specifies whether the memory that this refers to is readonly, allowing for the elimination of redundant loads.
+        readonly: bool,
+    },
+
+    /// Value is an offset from another global value.
+    IAddImm {
         /// The base pointer global value.
         base: GlobalValue,
 
-        /// Byte offset to be added to the loaded value.
-        offset: Offset32,
+        /// Byte offset to be added to the value.
+        offset: Imm64,
 
-        /// Type of the loaded value.
-        memory_type: Type,
+        /// Type of the iadd.
+        global_type: Type,
     },
 
-    /// Value is identified by a symbolic name. Cranelift itself does not interpret this name;
-    /// it's used by embedders to link with other data structures.
-    Sym {
+    /// Value is symbolic, meaning it's a name which will be resolved to an
+    /// actual value later (eg. by linking). Cranelift itself does not interpret
+    /// this name; it's used by embedders to link with other data structures.
+    ///
+    /// For now, symbolic values always have pointer type, and represent
+    /// addresses, however in the future they could be used to represent other
+    /// things as well.
+    Symbol {
         /// The symbolic name.
         name: ExternalName,
 
+        /// Offset from the symbol. This can be used instead of IAddImm to represent folding an
+        /// offset into a symbol.
+        offset: Imm64,
+
         /// Will this symbol be defined nearby, such that it will always be a certain distance
         /// away, after linking? If so, references to it can avoid going through a GOT. Note that
         /// symbols meant to be preemptible cannot be colocated.
         colocated: bool,
     },
 }
 
 impl GlobalValueData {
-    /// Assume that `self` is an `GlobalValueData::Sym` and return its name.
+    /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
     pub fn symbol_name(&self) -> &ExternalName {
         match *self {
-            GlobalValueData::Sym { ref name, .. } => name,
+            GlobalValueData::Symbol { ref name, .. } => name,
             _ => panic!("only symbols have names"),
         }
     }
 
     /// Return the type of this global.
     pub fn global_type(&self, isa: &TargetIsa) -> Type {
         match *self {
-            GlobalValueData::VMContext { .. } | GlobalValueData::Sym { .. } => isa.pointer_type(),
-            GlobalValueData::Deref { memory_type, .. } => memory_type,
+            GlobalValueData::VMContext { .. } | GlobalValueData::Symbol { .. } => {
+                isa.pointer_type()
+            }
+            GlobalValueData::IAddImm { global_type, .. }
+            | GlobalValueData::Load { global_type, .. } => global_type,
         }
     }
 }
 
 impl fmt::Display for GlobalValueData {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            GlobalValueData::VMContext { offset } => write!(f, "vmctx{}", offset),
-            GlobalValueData::Deref {
+            GlobalValueData::VMContext => write!(f, "vmctx"),
+            GlobalValueData::Load {
                 base,
                 offset,
-                memory_type,
-            } => write!(f, "deref({}){}: {}", base, offset, memory_type),
-            GlobalValueData::Sym {
+                global_type,
+                readonly,
+            } => write!(
+                f,
+                "load.{} notrap aligned {}{}{}",
+                global_type,
+                if readonly { "readonly " } else { "" },
+                base,
+                offset
+            ),
+            GlobalValueData::IAddImm {
+                global_type,
+                base,
+                offset,
+            } => write!(f, "iadd_imm.{} {}, {}", global_type, base, offset),
+            GlobalValueData::Symbol {
                 ref name,
+                offset,
                 colocated,
             } => {
                 if colocated {
                     write!(f, "colocated ")?;
                 }
-                write!(f, "globalsym {}", name)
+                write!(f, "symbol {}", name)?;
+                let offset_val: i64 = offset.into();
+                if offset_val > 0 {
+                    write!(f, "+")?;
+                }
+                if offset_val != 0 {
+                    write!(f, "{}", offset)?;
+                }
+                Ok(())
             }
         }
     }
 }
--- a/third_party/rust/cranelift-codegen/src/ir/immediates.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/immediates.rs
@@ -209,16 +209,36 @@ impl FromStr for Uimm32 {
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Offset32(i32);
 
 impl Offset32 {
     /// Create a new `Offset32` representing the signed number `x`.
     pub fn new(x: i32) -> Self {
         Offset32(x)
     }
+
+    /// Create a new `Offset32` representing the signed number `x` if possible.
+    pub fn try_from_i64(x: i64) -> Option<Self> {
+        let casted = x as i32;
+        if casted as i64 == x {
+            Some(Self::new(casted))
+        } else {
+            None
+        }
+    }
+
+    /// Add in the signed number `x` if possible.
+    pub fn try_add_i64(self, x: i64) -> Option<Self> {
+        let casted = x as i32;
+        if casted as i64 == x {
+            self.0.checked_add(casted).map(Self::new)
+        } else {
+            None
+        }
+    }
 }
 
 impl Into<i32> for Offset32 {
     fn into(self) -> i32 {
         self.0
     }
 }
 
--- a/third_party/rust/cranelift-codegen/src/ir/instructions.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/instructions.rs
@@ -189,17 +189,20 @@ impl InstructionData {
                 ref args,
                 ..
             } => BranchInfo::SingleDest(destination, &args.as_slice(pool)[1..]),
             InstructionData::BranchIcmp {
                 destination,
                 ref args,
                 ..
             } => BranchInfo::SingleDest(destination, &args.as_slice(pool)[2..]),
-            InstructionData::BranchTable { table, .. } => BranchInfo::Table(table),
+            InstructionData::BranchTable {
+                table, destination, ..
+            } => BranchInfo::Table(table, Some(destination)),
+            InstructionData::IndirectJump { table, .. } => BranchInfo::Table(table, None),
             _ => {
                 debug_assert!(!self.opcode().is_branch());
                 BranchInfo::NotABranch
             }
         }
     }
 
     /// Get the single destination of this branch instruction, if it is a single destination
@@ -208,17 +211,17 @@ impl InstructionData {
     /// Multi-destination branches like `br_table` return `None`.
     pub fn branch_destination(&self) -> Option<Ebb> {
         match *self {
             InstructionData::Jump { destination, .. }
             | InstructionData::Branch { destination, .. }
             | InstructionData::BranchInt { destination, .. }
             | InstructionData::BranchFloat { destination, .. }
             | InstructionData::BranchIcmp { destination, .. } => Some(destination),
-            InstructionData::BranchTable { .. } => None,
+            InstructionData::BranchTable { .. } | InstructionData::IndirectJump { .. } => None,
             _ => {
                 debug_assert!(!self.opcode().is_branch());
                 None
             }
         }
     }
 
     /// Get a mutable reference to the single destination of this branch instruction, if it is a
@@ -279,18 +282,18 @@ pub enum BranchInfo<'a> {
     /// This is not a branch or jump instruction.
     /// This instruction will not transfer control to another EBB in the function, but it may still
     /// affect control flow by returning or trapping.
     NotABranch,
 
     /// This is a branch or jump to a single destination EBB, possibly taking value arguments.
     SingleDest(Ebb, &'a [Value]),
 
-    /// This is a jump table branch which can have many destination EBBs.
-    Table(JumpTable),
+    /// This is a jump table branch which can have many destination EBBs and maybe one default EBB.
+    Table(JumpTable, Option<Ebb>),
 }
 
 /// Information about call instructions.
 pub enum CallInfo<'a> {
     /// This is not a call instruction.
     NotACall,
 
     /// This is a direct call to an external function declared in the preamble. See
--- a/third_party/rust/cranelift-codegen/src/ir/jumptable.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/jumptable.rs
@@ -1,180 +1,119 @@
 //! Jump table representation.
 //!
 //! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
 //! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
 
 use ir::entities::Ebb;
-use packed_option::PackedOption;
 use std::fmt::{self, Display, Formatter};
-use std::iter;
-use std::slice;
+use std::slice::{Iter, IterMut};
 use std::vec::Vec;
 
 /// Contents of a jump table.
 ///
-/// All jump tables use 0-based indexing and are expected to be densely populated. They don't need
-/// to be completely populated, though. Individual entries can be missing.
+/// All jump tables use 0-based indexing and densely populated.
 #[derive(Clone)]
 pub struct JumpTableData {
-    // Table entries, using `None` as a placeholder for missing entries.
-    table: Vec<PackedOption<Ebb>>,
-
-    // How many `None` holes in table?
-    holes: usize,
+    // Table entries.
+    table: Vec<Ebb>,
 }
 
 impl JumpTableData {
     /// Create a new empty jump table.
     pub fn new() -> Self {
-        Self {
-            table: Vec::new(),
-            holes: 0,
-        }
+        Self { table: Vec::new() }
     }
 
     /// Create a new empty jump table with the specified capacity.
     pub fn with_capacity(capacity: usize) -> Self {
         Self {
             table: Vec::with_capacity(capacity),
-            holes: 0,
         }
     }
 
     /// Get the number of table entries.
     pub fn len(&self) -> usize {
         self.table.len()
     }
 
-    /// Set a table entry.
-    ///
-    /// The table will grow as needed to fit `idx`.
-    pub fn set_entry(&mut self, idx: usize, dest: Ebb) {
-        // Resize table to fit `idx`.
-        if idx >= self.table.len() {
-            self.holes += idx - self.table.len();
-            self.table.resize(idx + 1, None.into());
-        } else if self.table[idx].is_none() {
-            // We're filling in an existing hole.
-            self.holes -= 1;
-        }
-        self.table[idx] = dest.into();
-    }
-
     /// Append a table entry.
     pub fn push_entry(&mut self, dest: Ebb) {
-        self.table.push(dest.into())
-    }
-
-    /// Clear a table entry.
-    ///
-    /// The `br_table` instruction will fall through if given an index corresponding to a cleared
-    /// table entry.
-    pub fn clear_entry(&mut self, idx: usize) {
-        if idx < self.table.len() && self.table[idx].is_some() {
-            self.holes += 1;
-            self.table[idx] = None.into();
-        }
-    }
-
-    /// Get the entry for `idx`, or `None`.
-    pub fn get_entry(&self, idx: usize) -> Option<Ebb> {
-        self.table.get(idx).and_then(|e| e.expand())
-    }
-
-    /// Enumerate over all `(idx, dest)` pairs in the table in order.
-    ///
-    /// This returns an iterator that skips any empty slots in the table.
-    pub fn entries(&self) -> Entries {
-        Entries(self.table.iter().cloned().enumerate())
+        self.table.push(dest)
     }
 
     /// Checks if any of the entries branch to `ebb`.
     pub fn branches_to(&self, ebb: Ebb) -> bool {
-        self.table
-            .iter()
-            .any(|target_ebb| target_ebb.expand() == Some(ebb))
+        self.table.iter().any(|target_ebb| *target_ebb == ebb)
+    }
+
+    /// Access the whole table as a slice.
+    pub fn as_slice(&self) -> &[Ebb] {
+        self.table.as_slice()
     }
 
     /// Access the whole table as a mutable slice.
-    pub fn as_mut_slice(&mut self) -> &mut [PackedOption<Ebb>] {
+    pub fn as_mut_slice(&mut self) -> &mut [Ebb] {
         self.table.as_mut_slice()
     }
-}
-
-/// Enumerate `(idx, dest)` pairs in order.
-pub struct Entries<'a>(iter::Enumerate<iter::Cloned<slice::Iter<'a, PackedOption<Ebb>>>>);
-
-impl<'a> Iterator for Entries<'a> {
-    type Item = (usize, Ebb);
 
-    fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            if let Some((idx, dest)) = self.0.next() {
-                if let Some(ebb) = dest.expand() {
-                    return Some((idx, ebb));
-                }
-            } else {
-                return None;
-            }
-        }
+    /// Returns an iterator over the table.
+    pub fn iter(&self) -> Iter<Ebb> {
+        self.table.iter()
+    }
+
+    /// Returns an iterator that allows modifying each value.
+    pub fn iter_mut(&mut self) -> IterMut<Ebb> {
+        self.table.iter_mut()
     }
 }
 
 impl Display for JumpTableData {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        match self.table.first().and_then(|e| e.expand()) {
-            None => write!(fmt, "jump_table 0")?,
-            Some(first) => write!(fmt, "jump_table {}", first)?,
+        write!(fmt, "jump_table [")?;
+        match self.table.first() {
+            None => (),
+            Some(first) => write!(fmt, "{}", first)?,
         }
-
-        for dest in self.table.iter().skip(1).map(|e| e.expand()) {
-            match dest {
-                None => write!(fmt, ", 0")?,
-                Some(ebb) => write!(fmt, ", {}", ebb)?,
-            }
+        for ebb in self.table.iter().skip(1) {
+            write!(fmt, ", {}", ebb)?;
         }
-        Ok(())
+        write!(fmt, "]")
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::JumpTableData;
     use entity::EntityRef;
     use ir::Ebb;
     use std::string::ToString;
-    use std::vec::Vec;
 
     #[test]
     fn empty() {
         let jt = JumpTableData::new();
 
-        assert_eq!(jt.get_entry(0), None);
-        assert_eq!(jt.get_entry(10), None);
+        assert_eq!(jt.as_slice().get(0), None);
+        assert_eq!(jt.as_slice().get(10), None);
 
-        assert_eq!(jt.to_string(), "jump_table 0");
+        assert_eq!(jt.to_string(), "jump_table []");
 
-        let v: Vec<(usize, Ebb)> = jt.entries().collect();
+        let v = jt.as_slice();
         assert_eq!(v, []);
     }
 
     #[test]
     fn insert() {