Repository: bytecodealliance/wasmtime
Pull request #1793 (2020-05-30 06:37:47)

💖 wiggle: escape rust keywords, allow witx literals
 # Overview

This commit makes changes to the `wiggle::from_witx` procedural in order
to allow for escaping strict and reserved Rust keywords.

Additionally, this commit introduces the ability to use a `witx_literal`
field in the `{..}` object provided as an argument to
`wiggle::from_witx`. This field allows for witx documents to be provided
as inline string literals.

Documentation comments are added to the methods of
`wiggle_generate::names::Names` struct responsible for generating
`proc_macro2::Ident` words.

 ## Keyword Escaping

Today, an interface that includes witx identifiers that conflict with
with Rust syntax will cause the `from_witx` macro to panic at
compilation time.

Here is a small example (adapted from
`/crates/wiggle/tests/keywords.rs`) that demonstrates this issue:

```
;; Attempts to define a module `self`, containing a trait `Self`. Both
;; of these are reserved keywords, and will thus cause a compilation
;; error.
(module $self
    (@interface func (export "betchya_cant_implement_this")
    )
)
```

Building off of code that (as of `master` today)
[demonstrates a strategy][esc] for escaping keywords, we introduce an
internal `escaping` module to `generate/src/config.rs` that contains
code responsible for escaping Rust keywords in a generalized manner.

[esc]: https://github.com/bytecodealliance/wasmtime/blob/0dd77d36f895df70c6e82758f23f553365c2f25f/crates/wiggle/generate/src/names.rs#L106

Some code related to special cases, such as accounting for
[`errno::2big`][err] while generating names for enum variants, is moved
into this module as well.

[err]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#-errno-enumu16

As mentioned in the document comments of this diff, we do not include
weak keywords like `'static` or `union`. Their semantics do not impact
us in the same way from a code generation perspective.

 ## witx_literal

First, some background. Trait names, type names, and so on use a
camel-cased naming convention.  As such, `Self` is the only keyword that
can potentially conflict with these identifiers. (See the [Rust
Reference][key] for a complete list of strict, reserved, and weak
keywords.)

When writing tests, this meant that many tests had to be outlined into
separate files, as items with the name `$self` could not be defined in
the same namespace. As such, it seemed like a worthwhile feature to
implement while the above work was being developed.

The most important function to note is the `load_document` inherent
method added to `WitxConf`, and that `WitxConf` is now an enum
containing either (a) a collection of paths, identical to its current
functionality, or (b) a single string literal.

Note that a witx document given to `from_witx` using a string literal
provided to `from_witx` cannot include `use (..)` directives, per
the `witx::parse` documentation.
(See: https://docs.rs/witx/0.8.5/witx/fn.parse.html)

Two newtypes, `Paths` and `Literal`, are introduced to facilitate the
parsing of `WitxConf` values. Their public API and trait implementations
has been kept to the minimum required to satisfy compilation in order to
limit the scope of this diff. Additional surface for external consumers
can be added in follow-up commits if deemed necessary in review.

:sparkling_heart: :sparkles: 


Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 7303ff56d..d7b3896f6 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,7 +15,7 @@ jobs:
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -28,7 +28,7 @@ jobs:
     name: Doc - build the book
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - run: |
@@ -50,7 +50,7 @@ jobs:
     name: Doc - build the API documentation
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -70,7 +70,7 @@ jobs:
     name: Check
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -112,7 +112,7 @@ jobs:
     name: Fuzz Targets
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -127,7 +127,7 @@ jobs:
     name: Rebuild Peephole Optimizers
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - name: Test `peepmatic`
@@ -175,7 +175,7 @@ jobs:
             os: windows-latest
             rust: stable
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -245,7 +245,7 @@ jobs:
     name: Meta deterministic check
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - name: Install Rust
@@ -284,7 +284,7 @@ jobs:
           qemu: qemu-aarch64 -L /usr/aarch64-linux-gnu
           qemu_target: aarch64-linux-user
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - uses: ./.github/actions/install-rust
@@ -407,7 +407,7 @@ jobs:
     needs: [doc_book, doc_api, build]
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
       with:
         submodules: true
     - run: rustup update stable && rustup default stable
@@ -513,7 +513,7 @@ jobs:
       CARGO_AUDIT_VERSION: 0.11.2
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v1
     - uses: actions/cache@v1
       with:
         path: ${{ runner.tool_cache }}/cargo-audit
diff --git a/Cargo.lock b/Cargo.lock
index be772cc0e..0859dec9b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2170,7 +2170,6 @@ dependencies = [
  "cfg-if",
  "lazy_static",
  "libc",
- "log",
  "region",
  "rustc-demangle",
  "target-lexicon",
diff --git a/RELEASES.md b/RELEASES.md
index 0ec09eae8..0bafdbf08 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -8,10 +8,7 @@ Unreleased
 
 ### Added
 
-* The [Commands and Reactors ABI] is now supported in the Rust API. `Linker::module`
-  loads a module and automatically handles Commands and Reactors semantics.
-
-[Commands and Reactors ABI]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi
+### Changed
 
 ### Fixed
 
diff --git a/build.rs b/build.rs
index 3841b8530..a6e2b7d8b 100644
--- a/build.rs
+++ b/build.rs
@@ -179,8 +179,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
             _ => (),
         },
         "Cranelift" => match (testsuite, testname) {
-            ("simd", "simd_store") => return false,
-            // Most simd tests are known to fail on aarch64 for now, it's going
+            // All simd tests are known to fail on aarch64 for now, it's going
             // to be a big chunk of work to implement them all there!
             ("simd", _) if target.contains("aarch64") => return true,
 
@@ -189,6 +188,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
             ("simd", "simd_f64x2") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 0 })])), got V128(0)
             ("simd", "simd_f64x2_arith") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 13835058055282163712 })])), got V128(255211775190703847615975447847722024960)
             ("simd", "simd_i64x2_arith") => return true, // FIXME Unsupported feature: proposed SIMD operator I64x2Mul
+            ("simd", "simd_lane") => return true, // FIXME invalid u8 number: constant out of range: (v8x16.shuffle -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
             ("simd", "simd_load") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16Shl
             ("simd", "simd_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16ShrS
 
diff --git a/cranelift/codegen/meta/src/isa/riscv/recipes.rs b/cranelift/codegen/meta/src/isa/riscv/recipes.rs
index 47acdbb04..1036d1556 100644
--- a/cranelift/codegen/meta/src/isa/riscv/recipes.rs
+++ b/cranelift/codegen/meta/src/isa/riscv/recipes.rs
@@ -64,7 +64,7 @@ pub(crate) fn define(shared_defs: &SharedDefinitions, regs: &IsaRegs) -> RecipeG
 
     // R-type with an immediate shift amount instead of rs2.
     recipes.push(
-        EncodingRecipeBuilder::new("Rshamt", &formats.binary_imm64, 4)
+        EncodingRecipeBuilder::new("Rshamt", &formats.binary_imm, 4)
             .operands_in(vec![gpr])
             .operands_out(vec![gpr])
             .emit("put_rshamt(bits, in_reg0, imm.into(), out_reg0, sink);"),
@@ -79,11 +79,11 @@ pub(crate) fn define(shared_defs: &SharedDefinitions, regs: &IsaRegs) -> RecipeG
     );
 
     recipes.push(
-        EncodingRecipeBuilder::new("Ii", &formats.binary_imm64, 4)
+        EncodingRecipeBuilder::new("Ii", &formats.binary_imm, 4)
             .operands_in(vec![gpr])
             .operands_out(vec![gpr])
             .inst_predicate(InstructionPredicate::new_is_signed_int(
-                &*formats.binary_imm64,
+                &*formats.binary_imm,
                 "imm",
                 12,
                 0,
diff --git a/cranelift/codegen/meta/src/isa/x86/encodings.rs b/cranelift/codegen/meta/src/isa/x86/encodings.rs
index 65df90725..7863e2bd8 100644
--- a/cranelift/codegen/meta/src/isa/x86/encodings.rs
+++ b/cranelift/codegen/meta/src/isa/x86/encodings.rs
@@ -1454,7 +1454,6 @@ fn define_alu(
     // x86 has a bitwise not instruction NOT.
     e.enc_i32_i64(bnot, rec_ur.opcodes(&NOT).rrr(2));
     e.enc_b32_b64(bnot, rec_ur.opcodes(&NOT).rrr(2));
-    e.enc_both(bnot.bind(B1), rec_ur.opcodes(&NOT).rrr(2));
 
     // Also add a `b1` encodings for the logic instructions.
     // TODO: Should this be done with 8-bit instructions? It would improve partial register
@@ -1634,7 +1633,6 @@ fn define_simd(
     let ushr_imm = shared.by_name("ushr_imm");
     let usub_sat = shared.by_name("usub_sat");
     let vconst = shared.by_name("vconst");
-    let vselect = shared.by_name("vselect");
     let x86_insertps = x86.by_name("x86_insertps");
     let x86_movlhps = x86.by_name("x86_movlhps");
     let x86_movsd = x86.by_name("x86_movsd");
@@ -1655,7 +1653,6 @@ fn define_simd(
     let x86_punpckl = x86.by_name("x86_punpckl");
 
     // Shorthands for recipes.
-    let rec_blend = r.template("blend");
     let rec_evex_reg_vvvv_rm_128 = r.template("evex_reg_vvvv_rm_128");
     let rec_f_ib = r.template("f_ib");
     let rec_fa = r.template("fa");
@@ -1725,20 +1722,6 @@ fn define_simd(
         e.enc_both_inferred(instruction, template);
     }
 
-    // SIMD vselect; controlling value of vselect is a boolean vector, so each lane should be
-    // either all ones or all zeroes - it makes it possible to always use 8-bit PBLENDVB;
-    // for 32/64-bit lanes we can also use BLENDVPS and BLENDVPD
-    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
-        let opcode = match ty.lane_bits() {
-            32 => &BLENDVPS,
-            64 => &BLENDVPD,
-            _ => &PBLENDVB,
-        };
-        let instruction = vselect.bind(vector(ty, sse_vector_size));
-        let template = rec_blend.opcodes(opcode);
-        e.enc_both_inferred_maybe_isap(instruction, template, Some(use_sse41_simd));
-    }
-
     // SIMD scalar_to_vector; this uses MOV to copy the scalar value to an XMM register; according
     // to the Intel manual: "When the destination operand is an XMM register, the source operand is
     // written to the low doubleword of the register and the register is zero-extended to 128 bits."
@@ -2286,7 +2269,8 @@ fn define_entity_ref(
     let rec_gvaddr8 = r.template("gvaddr8");
     let rec_pcrel_fnaddr8 = r.template("pcrel_fnaddr8");
     let rec_pcrel_gvaddr8 = r.template("pcrel_gvaddr8");
-    let rec_spaddr_id = r.template("spaddr_id");
+    let rec_spaddr4_id = r.template("spaddr4_id");
+    let rec_spaddr8_id = r.template("spaddr8_id");
 
     // Predicates shorthands.
     let all_ones_funcaddrs_and_not_is_pic =
@@ -2374,8 +2358,8 @@ fn define_entity_ref(
     //
     // TODO: Add encoding rules for stack_load and stack_store, so that they
     // don't get legalized to stack_addr + load/store.
-    e.enc64(stack_addr.bind(I64), rec_spaddr_id.opcodes(&LEA).rex().w());
-    e.enc32(stack_addr.bind(I32), rec_spaddr_id.opcodes(&LEA));
+    e.enc32(stack_addr.bind(I32), rec_spaddr4_id.opcodes(&LEA));
+    e.enc64(stack_addr.bind(I64), rec_spaddr8_id.opcodes(&LEA).rex().w());
 
     // Constant addresses (PIC).
     e.enc64(const_addr.bind(I64), rec_const_addr.opcodes(&LEA).rex().w());
diff --git a/cranelift/codegen/meta/src/isa/x86/instructions.rs b/cranelift/codegen/meta/src/isa/x86/instructions.rs
index f516a928d..267593735 100644
--- a/cranelift/codegen/meta/src/isa/x86/instructions.rs
+++ b/cranelift/codegen/meta/src/isa/x86/instructions.rs
@@ -283,7 +283,7 @@ pub(crate) fn define(
     Packed Shuffle Doublewords -- copies data from either memory or lanes in an extended
     register and re-orders the data according to the passed immediate byte.
     "#,
-            &formats.binary_imm8,
+            &formats.extract_lane,
         )
         .operands_in(vec![a, i]) // TODO allow copying from memory here (need more permissive type than TxN)
         .operands_out(vec![a]),
@@ -314,7 +314,7 @@ pub(crate) fn define(
         The lane index, ``Idx``, is an immediate value, not an SSA value. It
         must indicate a valid lane index for the type of ``x``.
         "#,
-            &formats.binary_imm8,
+            &formats.extract_lane,
         )
         .operands_in(vec![x, Idx])
         .operands_out(vec![a]),
@@ -342,9 +342,9 @@ pub(crate) fn define(
         The lane index, ``Idx``, is an immediate value, not an SSA value. It
         must indicate a valid lane index for the type of ``x``.
         "#,
-            &formats.ternary_imm8,
+            &formats.insert_lane,
         )
-        .operands_in(vec![x, y, Idx])
+        .operands_in(vec![x, Idx, y])
         .operands_out(vec![a]),
     );
 
@@ -369,9 +369,9 @@ pub(crate) fn define(
         extracted from and which it is inserted to. This is similar to x86_pinsr but inserts
         floats, which are already stored in an XMM register.
         "#,
-            &formats.ternary_imm8,
+            &formats.insert_lane,
         )
-        .operands_in(vec![x, y, Idx])
+        .operands_in(vec![x, Idx, y])
         .operands_out(vec![a]),
     );
 
diff --git a/cranelift/codegen/meta/src/isa/x86/legalize.rs b/cranelift/codegen/meta/src/isa/x86/legalize.rs
index 5d7e3c761..3b073c1fa 100644
--- a/cranelift/codegen/meta/src/isa/x86/legalize.rs
+++ b/cranelift/codegen/meta/src/isa/x86/legalize.rs
@@ -378,7 +378,6 @@ fn define_simd(shared: &mut SharedDefinitions, x86_instructions: &InstructionGro
     let vconst = insts.by_name("vconst");
     let vall_true = insts.by_name("vall_true");
     let vany_true = insts.by_name("vany_true");
-    let vselect = insts.by_name("vselect");
 
     let x86_packss = x86_instructions.by_name("x86_packss");
     let x86_pmaxs = x86_instructions.by_name("x86_pmaxs");
@@ -460,7 +459,7 @@ fn define_simd(shared: &mut SharedDefinitions, x86_instructions: &InstructionGro
                 // Move into the lowest 16 bits of an XMM register.
                 def!(a = scalar_to_vector(x)),
                 // Insert the value again but in the next lowest 16 bits.
-                def!(b = insertlane(a, x, uimm8_one)),
+                def!(b = insertlane(a, uimm8_one, x)),
                 // No instruction emitted; pretend this is an I32x4 so we can use PSHUFD.
                 def!(c = raw_bitcast_any16x8_to_i32x4(b)),
                 // Broadcast the bytes in the XMM register with PSHUFD.
@@ -494,7 +493,7 @@ fn define_simd(shared: &mut SharedDefinitions, x86_instructions: &InstructionGro
                 // Move into the lowest 64 bits of an XMM register.
                 def!(a = scalar_to_vector(x)),
                 // Move into the highest 64 bits of the same XMM register.
-                def!(y = insertlane(a, x, uimm8_one)),
+                def!(y = insertlane(a, uimm8_one, x)),
             ],
         );
     }
@@ -568,11 +567,11 @@ fn define_simd(shared: &mut SharedDefinitions, x86_instructions: &InstructionGro
                 // Use scalar operations to shift the first lane.
                 def!(a = extractlane(x, uimm8_zero)),
                 def!(b = sshr_scalar_lane0(a, y)),
-                def!(c = insertlane(x, b, uimm8_zero)),
+                def!(c = insertlane(x, uimm8_zero, b)),
                 // Do the same for the second lane.
                 def!(d = extractlane(x, uimm8_one)),
                 def!(e = sshr_scalar_lane1(d, y)),
-                def!(z = insertlane(c, e, uimm8_one)),
+                def!(z = insertlane(c, uimm8_one, e)),
             ],
         );
     }
@@ -590,17 +589,6 @@ fn define_simd(shared: &mut SharedDefinitions, x86_instructions: &InstructionGro
         );
     }
 
-    // SIMD vselect; replace with bitselect if BLEND* instructions are not available.
-    // This works, because each lane of boolean vector is filled with zeroes or ones.
-    for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
-        let vselect = vselect.bind(vector(ty, sse_vector_size));
-        let raw_bitcast = raw_bitcast.bind(vector(ty, sse_vector_size));
-        narrow.legalize(
-            def!(d = vselect(c, x, y)),
-            vec![def!(a = raw_bitcast(c)), def!(d = bitselect(a, x, y))],
-        );
-    }
-
     // SIMD vany_true
     let ne = Literal::enumerator_for(&imm.intcc, "ne");
     for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
diff --git a/cranelift/codegen/meta/src/isa/x86/opcodes.rs b/cranelift/codegen/meta/src/isa/x86/opcodes.rs
index 74dff216e..d34761d24 100644
--- a/cranelift/codegen/meta/src/isa/x86/opcodes.rs
+++ b/cranelift/codegen/meta/src/isa/x86/opcodes.rs
@@ -54,14 +54,6 @@ pub static BIT_SCAN_FORWARD: [u8; 2] = [0x0f, 0xbc];
 /// Bit scan reverse (stores index of first encountered 1 from the back).
 pub static BIT_SCAN_REVERSE: [u8; 2] = [0x0f, 0xbd];
 
-/// Select packed single-precision floating-point values from xmm1 and xmm2/m128
-/// from mask specified in XMM0 and store the values into xmm1 (SSE4.1).
-pub static BLENDVPS: [u8; 4] = [0x66, 0x0f, 0x38, 0x14];
-
-/// Select packed double-precision floating-point values from xmm1 and xmm2/m128
-/// from mask specified in XMM0 and store the values into xmm1 (SSE4.1).
-pub static BLENDVPD: [u8; 4] = [0x66, 0x0f, 0x38, 0x15];
-
 /// Call near, relative, displacement relative to next instruction (sign-extended).
 pub static CALL_RELATIVE: [u8; 1] = [0xe8];
 
@@ -343,10 +335,6 @@ pub static PAVGB: [u8; 3] = [0x66, 0x0f, 0xE0];
 /// Average packed unsigned word integers from xmm2/m128 and xmm1 with rounding (SSE2).
 pub static PAVGW: [u8; 3] = [0x66, 0x0f, 0xE3];
 
-/// Select byte values from xmm1 and xmm2/m128 from mask specified in the high bit of each byte
-/// in XMM0 and store the values into xmm1 (SSE4.1).
-pub static PBLENDVB: [u8; 4] = [0x66, 0x0f, 0x38, 0x10];
-
 /// Compare packed data for equal (SSE2).
 pub static PCMPEQB: [u8; 3] = [0x66, 0x0f, 0x74];
 
diff --git a/cranelift/codegen/meta/src/isa/x86/recipes.rs b/cranelift/codegen/meta/src/isa/x86/recipes.rs
index 0cfd83d37..0af1dd29a 100644
--- a/cranelift/codegen/meta/src/isa/x86/recipes.rs
+++ b/cranelift/codegen/meta/src/isa/x86/recipes.rs
@@ -427,7 +427,6 @@ pub(crate) fn define<'shared>(
     let reg_rcx = Register::new(gpr, regs.regunit_by_name(gpr, "rcx"));
     let reg_rdx = Register::new(gpr, regs.regunit_by_name(gpr, "rdx"));
     let reg_r15 = Register::new(gpr, regs.regunit_by_name(gpr, "r15"));
-    let reg_xmm0 = Register::new(fpr, regs.regunit_by_name(fpr, "xmm0"));
 
     // Stack operand with a 32-bit signed displacement from either RBP or RSP.
     let stack_gpr32 = Stack::new(gpr);
@@ -608,12 +607,12 @@ pub(crate) fn define<'shared>(
     // XX /r with FPR ins and outs. A form with a byte immediate.
     {
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("fa_ib", &formats.ternary_imm8, 2)
+            EncodingRecipeBuilder::new("fa_ib", &formats.insert_lane, 2)
                 .operands_in(vec![fpr, fpr])
                 .operands_out(vec![0])
                 .inst_predicate(InstructionPredicate::new_is_unsigned_int(
-                    &*formats.ternary_imm8,
-                    "imm",
+                    &*formats.insert_lane,
+                    "lane",
                     8,
                     0,
                 ))
@@ -621,7 +620,7 @@ pub(crate) fn define<'shared>(
                     r#"
                     {{PUT_OP}}(bits, rex2(in_reg1, in_reg0), sink);
                     modrm_rr(in_reg1, in_reg0, sink);
-                    let imm: i64 = imm.into();
+                    let imm:i64 = lane.into();
                     sink.put1(imm as u8);
                 "#,
                 ),
@@ -905,32 +904,14 @@ pub(crate) fn define<'shared>(
         .inferred_rex_compute_size("size_with_inferred_rex_for_inreg1"),
     );
 
-    // XX /r for BLEND* instructions
-    recipes.add_template_inferred(
-        EncodingRecipeBuilder::new("blend", &formats.ternary, 1)
-            .operands_in(vec![
-                OperandConstraint::FixedReg(reg_xmm0),
-                OperandConstraint::RegClass(fpr),
-                OperandConstraint::RegClass(fpr),
-            ])
-            .operands_out(vec![2])
-            .emit(
-                r#"
-                    {{PUT_OP}}(bits, rex2(in_reg1, in_reg2), sink);
-                    modrm_rr(in_reg1, in_reg2, sink);
-                "#,
-            ),
-        "size_with_inferred_rex_for_inreg1_inreg2",
-    );
-
     // XX /n ib with 8-bit immediate sign-extended.
     {
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("r_ib", &formats.binary_imm64, 2)
+            EncodingRecipeBuilder::new("r_ib", &formats.binary_imm, 2)
                 .operands_in(vec![gpr])
                 .operands_out(vec![0])
                 .inst_predicate(InstructionPredicate::new_is_signed_int(
-                    &*formats.binary_imm64,
+                    &*formats.binary_imm,
                     "imm",
                     8,
                     0,
@@ -947,11 +928,11 @@ pub(crate) fn define<'shared>(
         );
 
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("f_ib", &formats.binary_imm64, 2)
+            EncodingRecipeBuilder::new("f_ib", &formats.binary_imm, 2)
                 .operands_in(vec![fpr])
                 .operands_out(vec![0])
                 .inst_predicate(InstructionPredicate::new_is_signed_int(
-                    &*formats.binary_imm64,
+                    &*formats.binary_imm,
                     "imm",
                     8,
                     0,
@@ -970,11 +951,11 @@ pub(crate) fn define<'shared>(
         // XX /n id with 32-bit immediate sign-extended.
         recipes.add_template(
             Template::new(
-                EncodingRecipeBuilder::new("r_id", &formats.binary_imm64, 5)
+                EncodingRecipeBuilder::new("r_id", &formats.binary_imm, 5)
                     .operands_in(vec![gpr])
                     .operands_out(vec![0])
                     .inst_predicate(InstructionPredicate::new_is_signed_int(
-                        &*formats.binary_imm64,
+                        &*formats.binary_imm,
                         "imm",
                         32,
                         0,
@@ -996,20 +977,20 @@ pub(crate) fn define<'shared>(
     // XX /r ib with 8-bit unsigned immediate (e.g. for pshufd)
     {
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("r_ib_unsigned_fpr", &formats.binary_imm8, 2)
+            EncodingRecipeBuilder::new("r_ib_unsigned_fpr", &formats.extract_lane, 2)
                 .operands_in(vec![fpr])
                 .operands_out(vec![fpr])
                 .inst_predicate(InstructionPredicate::new_is_unsigned_int(
-                    &*formats.binary_imm8,
-                    "imm",
+                    &*formats.extract_lane,
+                    "lane",
                     8,
                     0,
-                ))
+                )) // TODO if the format name is changed then "lane" should be renamed to something more appropriate--ordering mask? broadcast immediate?
                 .emit(
                     r#"
                     {{PUT_OP}}(bits, rex2(in_reg0, out_reg0), sink);
                     modrm_rr(in_reg0, out_reg0, sink);
-                    let imm: i64 = imm.into();
+                    let imm:i64 = lane.into();
                     sink.put1(imm as u8);
                 "#,
                 ),
@@ -1020,17 +1001,17 @@ pub(crate) fn define<'shared>(
     // XX /r ib with 8-bit unsigned immediate (e.g. for extractlane)
     {
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("r_ib_unsigned_gpr", &formats.binary_imm8, 2)
+            EncodingRecipeBuilder::new("r_ib_unsigned_gpr", &formats.extract_lane, 2)
                 .operands_in(vec![fpr])
                 .operands_out(vec![gpr])
                 .inst_predicate(InstructionPredicate::new_is_unsigned_int(
-                    &*formats.binary_imm8, "imm", 8, 0,
+                    &*formats.extract_lane, "lane", 8, 0,
                 ))
                 .emit(
                     r#"
                     {{PUT_OP}}(bits, rex2(out_reg0, in_reg0), sink);
                     modrm_rr(out_reg0, in_reg0, sink); // note the flipped register in the ModR/M byte
-                    let imm: i64 = imm.into();
+                    let imm:i64 = lane.into();
                     sink.put1(imm as u8);
                 "#,
                 ), "size_with_inferred_rex_for_inreg0_outreg0"
@@ -1040,12 +1021,12 @@ pub(crate) fn define<'shared>(
     // XX /r ib with 8-bit unsigned immediate (e.g. for insertlane)
     {
         recipes.add_template_inferred(
-            EncodingRecipeBuilder::new("r_ib_unsigned_r", &formats.ternary_imm8, 2)
+            EncodingRecipeBuilder::new("r_ib_unsigned_r", &formats.insert_lane, 2)
                 .operands_in(vec![fpr, gpr])
                 .operands_out(vec![0])
                 .inst_predicate(InstructionPredicate::new_is_unsigned_int(
-                    &*formats.ternary_imm8,
-                    "imm",
+                    &*formats.insert_lane,
+                    "lane",
                     8,
                     0,
                 ))
@@ -1053,7 +1034,7 @@ pub(crate) fn define<'shared>(
                     r#"
                     {{PUT_OP}}(bits, rex2(in_reg1, in_reg0), sink);
                     modrm_rr(in_reg1, in_reg0, sink);
-                    let imm: i64 = imm.into();
+                    let imm:i64 = lane.into();
                     sink.put1(imm as u8);
                 "#,
                 ),
@@ -1451,7 +1432,23 @@ pub(crate) fn define<'shared>(
     // TODO Alternative forms for 8-bit immediates, when applicable.
 
     recipes.add_template_recipe(
-        EncodingRecipeBuilder::new("spaddr_id", &formats.stack_load, 6)
+        EncodingRecipeBuilder::new("spaddr4_id", &formats.stack_load, 6)
+            .operands_out(vec![gpr])
+            .emit(
+                r#"
+                    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);
+                "#,
+            ),
+    );
+
+    recipes.add_template_recipe(
+        EncodingRecipeBuilder::new("spaddr8_id", &formats.stack_load, 6)
             .operands_out(vec![gpr])
             .emit(
                 r#"
@@ -2874,12 +2871,12 @@ pub(crate) fn define<'shared>(
 
     {
         let has_small_offset =
-            InstructionPredicate::new_is_signed_int(&*formats.binary_imm64, "imm", 8, 0);
+            InstructionPredicate::new_is_signed_int(&*formats.binary_imm, "imm", 8, 0);
 
         // XX /n, MI form with imm8.
         recipes.add_template(
             Template::new(
-                EncodingRecipeBuilder::new("rcmp_ib", &formats.binary_imm64, 2)
+                EncodingRecipeBuilder::new("rcmp_ib", &formats.binary_imm, 2)
                     .operands_in(vec![gpr])
                     .operands_out(vec![reg_rflags])
                     .inst_predicate(has_small_offset)
@@ -2897,12 +2894,12 @@ pub(crate) fn define<'shared>(
         );
 
         let has_big_offset =
-            InstructionPredicate::new_is_signed_int(&*formats.binary_imm64, "imm", 32, 0);
+            InstructionPredicate::new_is_signed_int(&*formats.binary_imm, "imm", 32, 0);
 
         // XX /n, MI form with imm32.
         recipes.add_template(
             Template::new(
-                EncodingRecipeBuilder::new("rcmp_id", &formats.binary_imm64, 5)
+                EncodingRecipeBuilder::new("rcmp_id", &formats.binary_imm, 5)
                     .operands_in(vec![gpr])
                     .operands_out(vec![reg_rflags])
                     .inst_predicate(has_big_offset)
diff --git a/cranelift/codegen/meta/src/shared/formats.rs b/cranelift/codegen/meta/src/shared/formats.rs
index 204f3fccb..03c09e2e2 100644
--- a/cranelift/codegen/meta/src/shared/formats.rs
+++ b/cranelift/codegen/meta/src/shared/formats.rs
@@ -4,7 +4,7 @@ use std::rc::Rc;
 
 pub(crate) struct Formats {
     pub(crate) binary: Rc<InstructionFormat>,
-    pub(crate) binary_imm64: Rc<InstructionFormat>,
+    pub(crate) binary_imm: Rc<InstructionFormat>,
     pub(crate) branch: Rc<InstructionFormat>,
     pub(crate) branch_float: Rc<InstructionFormat>,
     pub(crate) branch_icmp: Rc<InstructionFormat>,
@@ -17,13 +17,14 @@ pub(crate) struct Formats {
     pub(crate) cond_trap: Rc<InstructionFormat>,
     pub(crate) copy_special: Rc<InstructionFormat>,
     pub(crate) copy_to_ssa: Rc<InstructionFormat>,
-    pub(crate) binary_imm8: Rc<InstructionFormat>,
+    pub(crate) extract_lane: Rc<InstructionFormat>,
     pub(crate) float_compare: Rc<InstructionFormat>,
     pub(crate) float_cond: Rc<InstructionFormat>,
     pub(crate) float_cond_trap: Rc<InstructionFormat>,
     pub(crate) func_addr: Rc<InstructionFormat>,
     pub(crate) heap_addr: Rc<InstructionFormat>,
     pub(crate) indirect_jump: Rc<InstructionFormat>,
+    pub(crate) insert_lane: Rc<InstructionFormat>,
     pub(crate) int_compare: Rc<InstructionFormat>,
     pub(crate) int_compare_imm: Rc<InstructionFormat>,
     pub(crate) int_cond: Rc<InstructionFormat>,
@@ -44,7 +45,6 @@ pub(crate) struct Formats {
     pub(crate) store_complex: Rc<InstructionFormat>,
     pub(crate) table_addr: Rc<InstructionFormat>,
     pub(crate) ternary: Rc<InstructionFormat>,
-    pub(crate) ternary_imm8: Rc<InstructionFormat>,
     pub(crate) trap: Rc<InstructionFormat>,
     pub(crate) unary: Rc<InstructionFormat>,
     pub(crate) unary_bool: Rc<InstructionFormat>,
@@ -76,9 +76,7 @@ impl Formats {
 
             binary: Builder::new("Binary").value().value().build(),
 
-            binary_imm8: Builder::new("BinaryImm8").value().imm(&imm.uimm8).build(),
-
-            binary_imm64: Builder::new("BinaryImm64").value().imm(&imm.imm64).build(),
+            binary_imm: Builder::new("BinaryImm").value().imm(&imm.imm64).build(),
 
             // The select instructions are controlled by the second VALUE operand.
             // The first VALUE operand is the controlling flag which has a derived type.
@@ -90,18 +88,23 @@ impl Formats {
                 .typevar_operand(1)
                 .build(),
 
-            ternary_imm8: Builder::new("TernaryImm8")
-                .value()
-                .imm(&imm.uimm8)
-                .value()
-                .build(),
-
             // Catch-all for instructions with many outputs and inputs and no immediate
             // operands.
             multiary: Builder::new("MultiAry").varargs().build(),
 
             nullary: Builder::new("NullAry").build(),
 
+            insert_lane: Builder::new("InsertLane")
+                .value()
+                .imm_with_name("lane", &imm.uimm8)
+                .value()
+                .build(),
+
+            extract_lane: Builder::new("ExtractLane")
+                .value()
+                .imm_with_name("lane", &imm.uimm8)
+                .build(),
+
             shuffle: Builder::new("Shuffle")
                 .value()
                 .value()
diff --git a/cranelift/codegen/meta/src/shared/instructions.rs b/cranelift/codegen/meta/src/shared/instructions.rs
index 62cd1ebeb..3a85f8059 100644
--- a/cranelift/codegen/meta/src/shared/instructions.rs
+++ b/cranelift/codegen/meta/src/shared/instructions.rs
@@ -559,9 +559,9 @@ fn define_simd_lane_access(
         The lane index, ``Idx``, is an immediate value, not an SSA value. It
         must indicate a valid lane index for the type of ``x``.
         "#,
-            &formats.ternary_imm8,
+            &formats.insert_lane,
         )
-        .operands_in(vec![x, y, Idx])
+        .operands_in(vec![x, Idx, y])
         .operands_out(vec![a]),
     );
 
@@ -579,7 +579,7 @@ fn define_simd_lane_access(
         may or may not be zeroed depending on the ISA but the type system should prevent using
         ``a`` as anything other than the extracted value.
         "#,
-            &formats.binary_imm8,
+            &formats.extract_lane,
         )
         .operands_in(vec![x, Idx])
         .operands_out(vec![a]),
@@ -2215,7 +2215,7 @@ pub(crate) fn define(
         Like `icmp_imm`, but returns integer CPU flags instead of testing
         a specific condition code.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![f]),
@@ -2460,7 +2460,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2475,7 +2475,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2489,7 +2489,7 @@ pub(crate) fn define(
 
         This operation traps if the divisor is zero.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2505,7 +2505,7 @@ pub(crate) fn define(
         representable in `B` bits two's complement. This only happens
         when `x = -2^{B-1}, Y = -1`.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2519,7 +2519,7 @@ pub(crate) fn define(
 
         This operation traps if the divisor is zero.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2533,7 +2533,7 @@ pub(crate) fn define(
 
         This operation traps if the divisor is zero.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2552,7 +2552,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2952,7 +2952,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2969,7 +2969,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -2986,7 +2986,7 @@ pub(crate) fn define(
         Polymorphic over all scalar integer types, but does not support vector
         types.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -3031,7 +3031,7 @@ pub(crate) fn define(
             r#"
         Rotate left by immediate.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -3043,7 +3043,7 @@ pub(crate) fn define(
             r#"
         Rotate right by immediate.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -3118,7 +3118,7 @@ pub(crate) fn define(
 
         The shift amount is masked to the size of ``x``.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -3132,7 +3132,7 @@ pub(crate) fn define(
 
         The shift amount is masked to the size of the register.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
@@ -3146,7 +3146,7 @@ pub(crate) fn define(
 
         The shift amount is masked to the size of the register.
         "#,
-            &formats.binary_imm64,
+            &formats.binary_imm,
         )
         .operands_in(vec![x, Y])
         .operands_out(vec![a]),
diff --git a/cranelift/codegen/src/binemit/stackmap.rs b/cranelift/codegen/src/binemit/stackmap.rs
index 27d87f896..10ae96a7c 100644
--- a/cranelift/codegen/src/binemit/stackmap.rs
+++ b/cranelift/codegen/src/binemit/stackmap.rs
@@ -15,8 +15,7 @@ const NUM_BITS: usize = core::mem::size_of::<Num>() * 8;
 /// The first value in the bitmap is of the lowest addressed slot on the stack.
 /// As all stacks in Isa's supported by Cranelift grow down, this means that
 /// first value is of the top of the stack and values proceed down the stack.
-#[derive(Clone, Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "enable-serde", derive(serde::Deserialize, serde::Serialize))]
+#[derive(Clone, Debug)]
 pub struct Stackmap {
     bitmap: Vec<BitSet<Num>>,
     mapped_words: u32,
diff --git a/cranelift/codegen/src/bitset.rs b/cranelift/codegen/src/bitset.rs
index 2cb0194b5..8035d80b9 100644
--- a/cranelift/codegen/src/bitset.rs
+++ b/cranelift/codegen/src/bitset.rs
@@ -5,14 +5,12 @@
 //!
 //! If you would like to add support for larger bitsets in the future, you need to change the trait
 //! bound Into<u32> and the u32 in the implementation of `max_bits()`.
-
 use core::convert::{From, Into};
 use core::mem::size_of;
 use core::ops::{Add, BitOr, Shl, Sub};
 
 /// A small bitset built on a single primitive integer type
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct BitSet<T>(pub T);
 
 impl<T> BitSet<T>
diff --git a/cranelift/codegen/src/ir/instructions.rs b/cranelift/codegen/src/ir/instructions.rs
index 653926a24..ccc47081a 100644
--- a/cranelift/codegen/src/ir/instructions.rs
+++ b/cranelift/codegen/src/ir/instructions.rs
@@ -306,7 +306,7 @@ impl InstructionData {
         let bit_width = ctrl_typevar.bits();
 
         match self {
-            Self::BinaryImm64 {
+            Self::BinaryImm {
                 opcode,
                 arg: _,
                 imm,
diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs
index 23b824fdb..8f388665b 100644
--- a/cranelift/codegen/src/isa/aarch64/abi.rs
+++ b/cranelift/codegen/src/isa/aarch64/abi.rs
@@ -280,7 +280,7 @@ fn in_int_reg(ty: ir::Type) -> bool {
 
 fn in_vec_reg(ty: ir::Type) -> bool {
     match ty {
-        types::F32 | types::F64 | types::I8X16 => true,
+        types::F32 | types::F64 => true,
         _ => false,
     }
 }
diff --git a/cranelift/codegen/src/isa/aarch64/inst/args.rs b/cranelift/codegen/src/isa/aarch64/inst/args.rs
index 3648eba2d..4b8142fbe 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/args.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/args.rs
@@ -480,14 +480,11 @@ impl ShowWithRRU for BranchTarget {
 }
 
 /// Type used to communicate the operand size of a machine instruction, as AArch64 has 32- and
-/// 64-bit variants of many instructions (and integer and floating-point registers) and 128-bit
-/// variants of vector instructions.
-/// TODO: Create a separate type for SIMD & floating-point operands.
+/// 64-bit variants of many instructions (and integer registers).
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum InstSize {
     Size32,
     Size64,
-    Size128,
 }
 
 impl InstSize {
@@ -510,13 +507,11 @@ impl InstSize {
     /// Convert from a needed width to the smallest size that fits.
     pub fn from_bits<I: Into<usize>>(bits: I) -> InstSize {
         let bits: usize = bits.into();
-        assert!(bits <= 128);
+        assert!(bits <= 64);
         if bits <= 32 {
             InstSize::Size32
-        } else if bits <= 64 {
-            InstSize::Size64
         } else {
-            InstSize::Size128
+            InstSize::Size64
         }
     }
 
@@ -525,12 +520,11 @@ impl InstSize {
         Self::from_bits(ty_bits(ty))
     }
 
-    /// Convert to I32, I64, or I128.
+    /// Convert to I32 or I64.
     pub fn to_ty(self) -> Type {
         match self {
             InstSize::Size32 => I32,
             InstSize::Size64 => I64,
-            InstSize::Size128 => I128,
         }
     }
 
@@ -538,9 +532,6 @@ impl InstSize {
         match self {
             InstSize::Size32 => 0,
             InstSize::Size64 => 1,
-            _ => {
-                panic!("Unexpected size");
-            }
         }
     }
 }
diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
index c0cbdd1f2..1bf59814b 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
@@ -295,8 +295,8 @@ fn enc_ccmp_imm(size: InstSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) ->
 }
 
 fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
+    debug_assert!(!is_16b); // to be supported later.
     0b00001110_101_00000_00011_1_00000_00000
-        | ((is_16b as u32) << 30)
         | machreg_to_vec(rd.to_reg())
         | (machreg_to_vec(rn) << 16)
         | (machreg_to_vec(rn) << 5)
@@ -918,9 +918,6 @@ impl MachInstEmit for Inst {
             &Inst::FpuMove64 { rd, rn } => {
                 sink.put4(enc_vecmov(/* 16b = */ false, rd, rn));
             }
-            &Inst::FpuMove128 { rd, rn } => {
-                sink.put4(enc_vecmov(/* 16b = */ true, rd, rn));
-            }
             &Inst::FpuRR { fpu_op, rd, rn } => {
                 let top22 = match fpu_op {
                     FPUOp1::Abs32 => 0b000_11110_00_1_000001_10000,
@@ -1076,22 +1073,6 @@ impl MachInstEmit for Inst {
                 inst.emit(sink, flags, state);
                 sink.put8(const_data.to_bits());
             }
-            &Inst::LoadFpuConst128 { rd, const_data } => {
-                let inst = Inst::FpuLoad128 {
-                    rd,
-                    mem: MemArg::Label(MemLabel::PCRel(8)),
-                    srcloc: None,
-                };
-                inst.emit(sink, flags, state);
-                let inst = Inst::Jump {
-                    dest: BranchTarget::ResolvedOffset(20),
-                };
-                inst.emit(sink, flags, state);
-
-                for i in const_data.to_le_bytes().iter() {
-                    sink.put1(*i);
-                }
-            }
             &Inst::FpuCSel32 { rd, rn, rm, cond } => {
                 sink.put4(enc_fcsel(rd, rn, rm, cond, InstSize::Size32));
             }
diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
index 1cf307d1d..989ce96f6 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
@@ -4,9 +4,7 @@
 #![allow(dead_code)]
 
 use crate::binemit::CodeOffset;
-use crate::ir::types::{
-    B1, B16, B32, B64, B8, F32, F32X2, F64, FFLAGS, I128, I16, I32, I64, I8, I8X16, IFLAGS,
-};
+use crate::ir::types::{B1, B16, B32, B64, B8, F32, F32X2, F64, FFLAGS, I16, I32, I64, I8, IFLAGS};
 use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode, Type};
 use crate::machinst::*;
 use crate::{settings, CodegenError, CodegenResult};
@@ -472,12 +470,6 @@ pub enum Inst {
         rn: Reg,
     },
 
-    /// Vector register move.
-    FpuMove128 {
-        rd: Writable<Reg>,
-        rn: Reg,
-    },
-
     /// 1-op FPU instruction.
     FpuRR {
         fpu_op: FPUOp1,
@@ -567,11 +559,6 @@ pub enum Inst {
         const_data: f64,
     },
 
-    LoadFpuConst128 {
-        rd: Writable<Reg>,
-        const_data: u128,
-    },
-
     /// Conversion: FP -> integer.
     FpuToInt {
         op: FpuToIntOp,
@@ -829,11 +816,6 @@ impl Inst {
                 rd: to_reg,
                 rm: from_reg,
             }
-        } else if from_reg.get_class() == RegClass::V128 {
-            Inst::FpuMove128 {
-                rd: to_reg,
-                rn: from_reg,
-            }
         } else {
             Inst::FpuMove64 {
                 rd: to_reg,
@@ -923,14 +905,6 @@ impl Inst {
             const_data: value,
         }
     }
-
-    /// Create an instruction that loads a 128-bit vector constant.
-    pub fn load_fp_constant128(rd: Writable<Reg>, value: u128) -> Inst {
-        Inst::LoadFpuConst128 {
-            rd,
-            const_data: value,
-        }
-    }
 }
 
 //=============================================================================
@@ -1070,10 +1044,6 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
             collector.add_def(rd);
             collector.add_use(rn);
         }
-        &Inst::FpuMove128 { rd, rn } => {
-            collector.add_def(rd);
-            collector.add_use(rn);
-        }
         &Inst::FpuRR { rd, rn, .. } => {
             collector.add_def(rd);
             collector.add_use(rn);
@@ -1124,9 +1094,7 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
             collector.add_use(rd);
             memarg_regs(mem, collector);
         }
-        &Inst::LoadFpuConst32 { rd, .. }
-        | &Inst::LoadFpuConst64 { rd, .. }
-        | &Inst::LoadFpuConst128 { rd, .. } => {
+        &Inst::LoadFpuConst32 { rd, .. } | &Inst::LoadFpuConst64 { rd, .. } => {
             collector.add_def(rd);
         }
         &Inst::FpuToInt { rd, rn, .. } => {
@@ -1522,13 +1490,6 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
             map_def(mapper, rd);
             map_use(mapper, rn);
         }
-        &mut Inst::FpuMove128 {
-            ref mut rd,
-            ref mut rn,
-        } => {
-            map_def(mapper, rd);
-            map_use(mapper, rn);
-        }
         &mut Inst::FpuRR {
             ref mut rd,
             ref mut rn,
@@ -1635,9 +1596,6 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
         &mut Inst::LoadFpuConst64 { ref mut rd, .. } => {
             map_def(mapper, rd);
         }
-        &mut Inst::LoadFpuConst128 { ref mut rd, .. } => {
-            map_def(mapper, rd);
-        }
         &mut Inst::FpuToInt {
             ref mut rd,
             ref mut rn,
@@ -1822,7 +1780,6 @@ impl MachInst for Inst {
         match self {
             &Inst::Mov { rd, rm } => Some((rd, rm)),
             &Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
-            &Inst::FpuMove128 { rd, rn } => Some((rd, rn)),
             _ => None,
         }
     }
@@ -1856,7 +1813,7 @@ impl MachInst for Inst {
     }
 
     fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
-        assert!(ty.bits() <= 128);
+        assert!(ty.bits() <= 64); // no vector support yet!
         Inst::mov(to_reg, from_reg)
     }
 
@@ -1908,7 +1865,6 @@ impl MachInst for Inst {
             I8 | I16 | I32 | I64 | B1 | B8 | B16 | B32 | B64 => Ok(RegClass::I64),
             F32 | F64 => Ok(RegClass::V128),
             IFLAGS | FFLAGS => Ok(RegClass::I64),
-            I8X16 => Ok(RegClass::V128),
             _ => Err(CodegenError::Unsupported(format!(
                 "Unexpected SSA-value type: {}",
                 ty
@@ -2279,11 +2235,6 @@ impl ShowWithRRU for Inst {
                 let rn = rn.show_rru(mb_rru);
                 format!("mov {}.8b, {}.8b", rd, rn)
             }
-            &Inst::FpuMove128 { rd, rn } => {
-                let rd = rd.to_reg().show_rru(mb_rru);
-                let rn = rn.show_rru(mb_rru);
-                format!("mov {}.16b, {}.16b", rd, rn)
-            }
             &Inst::FpuRR { fpu_op, rd, rn } => {
                 let (op, sizesrc, sizedest) = match fpu_op {
                     FPUOp1::Abs32 => ("fabs", InstSize::Size32, InstSize::Size32),
@@ -2409,10 +2360,6 @@ impl ShowWithRRU for Inst {
                 let rd = show_freg_sized(rd.to_reg(), mb_rru, InstSize::Size64);
                 format!("ldr {}, pc+8 ; b 12 ; data.f64 {}", rd, const_data)
             }
-            &Inst::LoadFpuConst128 { rd, const_data } => {
-                let rd = show_freg_sized(rd.to_reg(), mb_rru, InstSize::Size128);
-                format!("ldr {}, pc+8 ; b 20 ; data.f128 0x{:032x}", rd, const_data)
-            }
             &Inst::FpuToInt { op, rd, rn } => {
                 let (op, sizesrc, sizedest) = match op {
                     FpuToIntOp::F32ToI32 => ("fcvtzs", InstSize::Size32, InstSize::Size32),
diff --git a/cranelift/codegen/src/isa/aarch64/inst/regs.rs b/cranelift/codegen/src/isa/aarch64/inst/regs.rs
index 7e13e33ac..242fb66fc 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/regs.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/regs.rs
@@ -276,17 +276,13 @@ pub fn show_ireg_sized(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: InstSiz
     s
 }
 
-/// Show a vector register.
+/// Show a vector register when its use as a 32-bit or 64-bit float is known.
 pub fn show_freg_sized(reg: Reg, mb_rru: Option<&RealRegUniverse>, size: InstSize) -> String {
     let mut s = reg.show_rru(mb_rru);
     if reg.get_class() != RegClass::V128 {
         return s;
     }
-    let prefix = match size {
-        InstSize::Size32 => "s",
-        InstSize::Size64 => "d",
-        InstSize::Size128 => "q",
-    };
+    let prefix = if size.is32() { "s" } else { "d" };
     s.replace_range(0..1, prefix);
     s
 }
diff --git a/cranelift/codegen/src/isa/aarch64/lower.rs b/cranelift/codegen/src/isa/aarch64/lower.rs
index 68ad4017e..eb4aafd55 100644
--- a/cranelift/codegen/src/isa/aarch64/lower.rs
+++ b/cranelift/codegen/src/isa/aarch64/lower.rs
@@ -142,31 +142,6 @@ pub(crate) fn input_to_shiftimm<C: LowerCtx<I = Inst>>(
     input_to_const(ctx, input).and_then(ShiftOpShiftImm::maybe_from_shift)
 }
 
-pub(crate) fn output_to_const_f128<C: LowerCtx<I = Inst>>(
-    ctx: &mut C,
-    out: InsnOutput,
-) -> Option<u128> {
-    if out.output > 0 {
-        None
-    } else {
-        let inst_data = ctx.data(out.insn);
-
-        match inst_data {
-            &InstructionData::UnaryConst {
-                opcode: _,
-                constant_handle,
-            } => {
-                let mut bytes = [0u8; 16];
-                let c = ctx.get_constant_data(constant_handle).clone().into_vec();
-                assert_eq!(c.len(), 16);
-                bytes.copy_from_slice(&c);
-                Some(u128::from_le_bytes(bytes))
-            }
-            _ => None,
-        }
-    }
-}
-
 /// How to handle narrow values loaded into registers; see note on `narrow_mode`
 /// parameter to `input_to_*` below.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -613,14 +588,6 @@ pub(crate) fn lower_constant_f64<C: LowerCtx<I = Inst>>(
     ctx.emit(Inst::load_fp_constant64(rd, value));
 }
 
-pub(crate) fn lower_constant_f128<C: LowerCtx<I = Inst>>(
-    ctx: &mut C,
-    rd: Writable<Reg>,
-    value: u128,
-) {
-    ctx.emit(Inst::load_fp_constant128(rd, value));
-}
-
 pub(crate) fn lower_condcode(cc: IntCC) -> Cond {
     match cc {
         IntCC::Equal => Cond::Eq,
@@ -712,7 +679,6 @@ pub fn ty_bits(ty: Type) -> usize {
         B64 | I64 | F64 => 64,
         B128 | I128 => 128,
         IFLAGS | FFLAGS => 32,
-        I8X16 => 128,
         _ => panic!("ty_bits() on unknown type: {:?}", ty),
     }
 }
@@ -720,7 +686,7 @@ pub fn ty_bits(ty: Type) -> usize {
 pub(crate) fn ty_is_int(ty: Type) -> bool {
     match ty {
         B1 | B8 | I8 | B16 | I16 | B32 | I32 | B64 | I64 => true,
-        F32 | F64 | B128 | I128 | I8X16 => false,
+        F32 | F64 | B128 | I128 => false,
         IFLAGS | FFLAGS => panic!("Unexpected flags type"),
         _ => panic!("ty_is_int() on unknown type: {:?}", ty),
     }
diff --git a/cranelift/codegen/src/isa/aarch64/lower_inst.rs b/cranelift/codegen/src/isa/aarch64/lower_inst.rs
index 2faa66941..2946e1647 100644
--- a/cranelift/codegen/src/isa/aarch64/lower_inst.rs
+++ b/cranelift/codegen/src/isa/aarch64/lower_inst.rs
@@ -875,7 +875,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
                 (32, _, true) => Inst::FpuLoad32 { rd, mem, srcloc },
                 (64, _, false) => Inst::ULoad64 { rd, mem, srcloc },
                 (64, _, true) => Inst::FpuLoad64 { rd, mem, srcloc },
-                (128, _, _) => Inst::FpuLoad128 { rd, mem, srcloc },
                 _ => panic!("Unsupported size in load"),
             });
         }
@@ -915,7 +914,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
                 (32, true) => Inst::FpuStore32 { rd, mem, srcloc },
                 (64, false) => Inst::Store64 { rd, mem, srcloc },
                 (64, true) => Inst::FpuStore64 { rd, mem, srcloc },
-                (128, _) => Inst::FpuStore128 { rd, mem, srcloc },
                 _ => panic!("Unsupported size in store"),
             });
         }
@@ -1344,13 +1342,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
             panic!("Branch opcode reached non-branch lowering logic!");
         }
 
-        Opcode::Vconst => {
-            let value = output_to_const_f128(ctx, outputs[0]).unwrap();
-            let rd = output_to_reg(ctx, outputs[0]);
-            lower_constant_f128(ctx, rd, value);
-        }
-
-        Opcode::Shuffle
+        Opcode::Vconst
+        | Opcode::Shuffle
         | Opcode::Vsplit
         | Opcode::Vconcat
         | Opcode::Vselect
diff --git a/cranelift/codegen/src/isa/riscv/mod.rs b/cranelift/codegen/src/isa/riscv/mod.rs
index e957367bb..8aa264f34 100644
--- a/cranelift/codegen/src/isa/riscv/mod.rs
+++ b/cranelift/codegen/src/isa/riscv/mod.rs
@@ -163,7 +163,7 @@ mod tests {
         let arg32 = func.dfg.append_block_param(block, types::I32);
 
         // Try to encode iadd_imm.i64 v1, -10.
-        let inst64 = InstructionData::BinaryImm64 {
+        let inst64 = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg64,
             imm: immediates::Imm64::new(-10),
@@ -176,7 +176,7 @@ mod tests {
         );
 
         // Try to encode iadd_imm.i64 v1, -10000.
-        let inst64_large = InstructionData::BinaryImm64 {
+        let inst64_large = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg64,
             imm: immediates::Imm64::new(-10000),
@@ -186,7 +186,7 @@ mod tests {
         assert!(isa.encode(&func, &inst64_large, types::I64).is_err());
 
         // Create an iadd_imm.i32 which is encodable in RV64.
-        let inst32 = InstructionData::BinaryImm64 {
+        let inst32 = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg32,
             imm: immediates::Imm64::new(10),
@@ -214,7 +214,7 @@ mod tests {
         let arg32 = func.dfg.append_block_param(block, types::I32);
 
         // Try to encode iadd_imm.i64 v1, -10.
-        let inst64 = InstructionData::BinaryImm64 {
+        let inst64 = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg64,
             imm: immediates::Imm64::new(-10),
@@ -224,7 +224,7 @@ mod tests {
         assert!(isa.encode(&func, &inst64, types::I64).is_err());
 
         // Try to encode iadd_imm.i64 v1, -10000.
-        let inst64_large = InstructionData::BinaryImm64 {
+        let inst64_large = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg64,
             imm: immediates::Imm64::new(-10000),
@@ -234,7 +234,7 @@ mod tests {
         assert!(isa.encode(&func, &inst64_large, types::I64).is_err());
 
         // Create an iadd_imm.i32 which is encodable in RV32.
-        let inst32 = InstructionData::BinaryImm64 {
+        let inst32 = InstructionData::BinaryImm {
             opcode: Opcode::IaddImm,
             arg: arg32,
             imm: immediates::Imm64::new(10),
diff --git a/cranelift/codegen/src/isa/x86/abi.rs b/cranelift/codegen/src/isa/x86/abi.rs
index d0308f73e..c072594b6 100644
--- a/cranelift/codegen/src/isa/x86/abi.rs
+++ b/cranelift/codegen/src/isa/x86/abi.rs
@@ -245,17 +245,24 @@ pub fn legalize_signature(
         isa_flags,
     );
 
-    // If we don't have enough available return registers
-    // to fit all of the return values, we need to backtrack and start
+    let sig_is_multi_return = sig.is_multi_return();
+
+    // If this is a multi-value return and we don't have enough available return
+    // registers to fit all of the return values, we need to backtrack and start
     // assigning locations all over again with a different strategy. In order to
     // do that, we need a copy of the original assigner for the returns.
-    let mut backup_rets = rets.clone();
+    let backup_rets_for_struct_return = if sig_is_multi_return {
+        Some(rets.clone())
+    } else {
+        None
+    };
 
     if let Some(new_returns) = legalize_args(&sig.returns, &mut rets) {
-        if new_returns
-            .iter()
-            .filter(|r| r.purpose == ArgumentPurpose::Normal)
-            .any(|r| !r.location.is_reg())
+        if sig.is_multi_return()
+            && new_returns
+                .iter()
+                .filter(|r| r.purpose == ArgumentPurpose::Normal)
+                .any(|r| !r.location.is_reg())
         {
             // The return values couldn't all fit into available return
             // registers. Introduce the use of a struct-return parameter.
@@ -276,6 +283,8 @@ pub fn legalize_signature(
                 _ => unreachable!("return pointer should always get a register assignment"),
             }
 
+            let mut backup_rets = backup_rets_for_struct_return.unwrap();
+
             // We're using the first return register for the return pointer (like
             // sys v does).
             let mut ret_ptr_return = AbiParam {
diff --git a/cranelift/codegen/src/isa/x86/enc_tables.rs b/cranelift/codegen/src/isa/x86/enc_tables.rs
index 19b08d58a..c00ca9735 100644
--- a/cranelift/codegen/src/isa/x86/enc_tables.rs
+++ b/cranelift/codegen/src/isa/x86/enc_tables.rs
@@ -246,20 +246,6 @@ fn size_with_inferred_rex_for_inreg0_inreg1(
     sizing.base_size + if needs_rex { 1 } else { 0 }
 }
 
-/// Infers whether a dynamic REX prefix will be emitted, based on second and third operand.
-fn size_with_inferred_rex_for_inreg1_inreg2(
-    sizing: &RecipeSizing,
-    _enc: Encoding,
-    inst: Inst,
-    divert: &RegDiversions,
-    func: &Function,
-) -> u8 {
-    // No need to check for REX.W in `needs_rex` because `infer_rex().w()` is not allowed.
-    let needs_rex = test_input(1, inst, divert, func, is_extended_reg)
-        || test_input(2, inst, divert, func, is_extended_reg);
-    sizing.base_size + if needs_rex { 1 } else { 0 }
-}
-
 /// Infers whether a dynamic REX prefix will be emitted, based on a single
 /// input register and a single output register.
 fn size_with_inferred_rex_for_inreg0_outreg0(
@@ -1195,10 +1181,10 @@ fn convert_extractlane(
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
-    if let ir::InstructionData::BinaryImm8 {
+    if let ir::InstructionData::ExtractLane {
         opcode: ir::Opcode::Extractlane,
         arg,
-        imm: lane,
+        lane,
     } = pos.func.dfg[inst]
     {
         // NOTE: the following legalization assumes that the upper bits of the XMM register do
@@ -1251,10 +1237,10 @@ fn convert_insertlane(
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
-    if let ir::InstructionData::TernaryImm8 {
+    if let ir::InstructionData::InsertLane {
         opcode: ir::Opcode::Insertlane,
         args: [vector, replacement],
-        imm: lane,
+        lane,
     } = pos.func.dfg[inst]
     {
         let value_type = pos.func.dfg.value_type(vector);
@@ -1269,7 +1255,7 @@ fn convert_insertlane(
                     pos.func
                         .dfg
                         .replace(inst)
-                        .x86_insertps(vector, replacement, immediate)
+                        .x86_insertps(vector, immediate, replacement)
                 }
                 F64X2 => {
                     let replacement_as_vector = pos.ins().raw_bitcast(F64X2, replacement); // only necessary due to SSA types
@@ -1297,7 +1283,7 @@ fn convert_insertlane(
             pos.func
                 .dfg
                 .replace(inst)
-                .x86_pinsr(vector, replacement, lane);
+                .x86_pinsr(vector, lane, replacement);
         }
     }
 }
@@ -1340,7 +1326,7 @@ fn expand_dword_to_xmm<'f>(
     if arg_type == I64 {
         let (arg_lo, arg_hi) = pos.ins().isplit(arg);
         let arg = pos.ins().scalar_to_vector(I32X4, arg_lo);
-        let arg = pos.ins().insertlane(arg, arg_hi, 1);
+        let arg = pos.ins().insertlane(arg, 1, arg_hi);
         let arg = pos.ins().raw_bitcast(I64X2, arg);
         arg
     } else {
diff --git a/cranelift/codegen/src/legalizer/boundary.rs b/cranelift/codegen/src/legalizer/boundary.rs
index 185e4c74f..7fb977a06 100644
--- a/cranelift/codegen/src/legalizer/boundary.rs
+++ b/cranelift/codegen/src/legalizer/boundary.rs
@@ -757,6 +757,12 @@ pub fn handle_call_abi(
     {
         legalize_sret_call(isa, pos, sig_ref, inst);
     } else {
+        // OK, we need to fix the call arguments to match the ABI signature.
+        let abi_args = pos.func.dfg.signatures[sig_ref].params.len();
+        legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
+            func.dfg.signatures[sig_ref].params[abi_arg]
+        });
+
         if !pos.func.dfg.signatures[sig_ref].returns.is_empty() {
             inst = legalize_inst_results(pos, |func, abi_res| {
                 func.dfg.signatures[sig_ref].returns[abi_res]
@@ -764,13 +770,6 @@ pub fn handle_call_abi(
         }
     }
 
-    // Go back and fix the call arguments to match the ABI signature.
-    pos.goto_inst(inst);
-    let abi_args = pos.func.dfg.signatures[sig_ref].params.len();
-    legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
-        func.dfg.signatures[sig_ref].params[abi_arg]
-    });
-
     debug_assert!(
         check_call_signature(&pos.func.dfg, inst).is_ok(),
         "Signature still wrong: {}, {}{}",
diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs
index fabfdecc6..76663450b 100644
--- a/cranelift/codegen/src/machinst/lower.rs
+++ b/cranelift/codegen/src/machinst/lower.rs
@@ -7,8 +7,8 @@ use crate::fx::{FxHashMap, FxHashSet};
 use crate::inst_predicates::{has_side_effect_or_load, is_constant_64bit};
 use crate::ir::instructions::BranchInfo;
 use crate::ir::{
-    ArgumentExtension, Block, Constant, ConstantData, ExternalName, Function, GlobalValueData,
-    Inst, InstructionData, MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef,
+    ArgumentExtension, Block, ExternalName, Function, GlobalValueData, Inst, InstructionData,
+    MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef,
 };
 use crate::machinst::{
     ABIBody, BlockIndex, BlockLoweringOrder, LoweredBlock, MachLabel, VCode, VCodeBuilder,
@@ -145,8 +145,6 @@ pub trait LowerCtx {
     /// `get_input()`. Codegen may not happen otherwise for the producing
     /// instruction if it has no side effects and no uses.
     fn use_input_reg(&mut self, input: LowerInput);
-    /// Retrieve constant data given a handle.
-    fn get_constant_data(&self, constant_handle: Constant) -> &ConstantData;
 }
 
 /// A representation of all of the ways in which an instruction input is
@@ -915,10 +913,6 @@ impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> {
         debug!("use_input_reg: vreg {:?} is needed", input.reg);
         self.vreg_needed[input.reg.get_index()] = true;
     }
-
-    fn get_constant_data(&self, constant_handle: Constant) -> &ConstantData {
-        self.f.dfg.constants.get(constant_handle)
-    }
 }
 
 /// Visit all successors of a block with a given visitor closure.
diff --git a/cranelift/codegen/src/peepmatic.rs b/cranelift/codegen/src/peepmatic.rs
index 1e2201940..1ea2031bf 100644
--- a/cranelift/codegen/src/peepmatic.rs
+++ b/cranelift/codegen/src/peepmatic.rs
@@ -378,7 +378,7 @@ fn intcc_to_peepmatic(cc: IntCC) -> ConditionCode {
 
 fn get_immediate(dfg: &DataFlowGraph, inst: Inst, i: usize) -> Part<ValueOrInst> {
     return match dfg[inst] {
-        InstructionData::BinaryImm64 { imm, .. } if i == 0 => imm.into(),
+        InstructionData::BinaryImm { imm, .. } if i == 0 => imm.into(),
         InstructionData::BranchIcmp { cond, .. } if i == 0 => intcc_to_peepmatic(cond).into(),
         InstructionData::BranchInt { cond, .. } if i == 0 => intcc_to_peepmatic(cond).into(),
         InstructionData::IntCompare { cond, .. } if i == 0 => intcc_to_peepmatic(cond).into(),
diff --git a/cranelift/codegen/src/postopt.rs b/cranelift/codegen/src/postopt.rs
index 426aab00b..3e27c90a3 100644
--- a/cranelift/codegen/src/postopt.rs
+++ b/cranelift/codegen/src/postopt.rs
@@ -341,7 +341,7 @@ fn optimize_complex_addresses(pos: &mut EncCursor, inst: Inst, isa: &dyn TargetI
                 }
                 _ => panic!("Unsupported load or store opcode"),
             },
-            InstructionData::BinaryImm64 {
+            InstructionData::BinaryImm {
                 opcode: Opcode::IaddImm,
                 arg,
                 imm,
diff --git a/cranelift/codegen/src/simple_preopt.rs b/cranelift/codegen/src/simple_preopt.rs
index 6903d18f6..2f47c7d91 100644
--- a/cranelift/codegen/src/simple_preopt.rs
+++ b/cranelift/codegen/src/simple_preopt.rs
@@ -142,7 +142,7 @@ fn package_up_divrem_info(
 /// Examine `inst` to see if it is a div or rem by a constant, and if so return the operands,
 /// signedness, operation size and div-vs-rem-ness in a handy bundle.
 fn get_div_info(inst: Inst, dfg: &DataFlowGraph) -> Option<DivRemByConstInfo> {
-    if let InstructionData::BinaryImm64 { opcode, arg, imm } = dfg[inst] {
+    if let InstructionData::BinaryImm { opcode, arg, imm } = dfg[inst] {
         let (is_signed, is_rem) = match opcode {
             Opcode::UdivImm => (false, false),
             Opcode::UremImm => (false, true),
@@ -656,7 +656,7 @@ mod simplify {
         dfg::ValueDef,
         immediates,
         instructions::{Opcode, ValueList},
-        types::{B8, I16, I32, I8},
+        types::{I16, I32, I8},
     };
     use std::marker::PhantomData;
 
@@ -704,7 +704,7 @@ mod simplify {
         imm: immediates::Imm64,
     ) -> bool {
         if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) {
-            if let InstructionData::BinaryImm64 {
+            if let InstructionData::BinaryImm {
                 opcode: Opcode::IshlImm,
                 arg: prev_arg,
                 imm: prev_imm,
@@ -784,7 +784,7 @@ mod simplify {
                         pos.func
                             .dfg
                             .replace(inst)
-                            .BinaryImm64(new_opcode, ty, imm, args[0]);
+                            .BinaryImm(new_opcode, ty, imm, args[0]);
 
                         // Repeat for BinaryImm simplification.
                         simplify(pos, inst, native_word_width);
@@ -804,7 +804,7 @@ mod simplify {
                         pos.func
                             .dfg
                             .replace(inst)
-                            .BinaryImm64(new_opcode, ty, imm, args[1]);
+                            .BinaryImm(new_opcode, ty, imm, args[1]);
                     }
                 }
             }
@@ -818,7 +818,7 @@ mod simplify {
                 }
             }
 
-            InstructionData::BinaryImm64 { opcode, arg, imm } => {
+            InstructionData::BinaryImm { opcode, arg, imm } => {
                 let ty = pos.func.dfg.ctrl_typevar(inst);
 
                 let mut arg = arg;
@@ -831,7 +831,7 @@ mod simplify {
                     | Opcode::BxorImm => {
                         // Fold binary_op(C2, binary_op(C1, x)) into binary_op(binary_op(C1, C2), x)
                         if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) {
-                            if let InstructionData::BinaryImm64 {
+                            if let InstructionData::BinaryImm {
                                 opcode: prev_opcode,
                                 arg: prev_arg,
                                 imm: prev_imm,
@@ -855,7 +855,7 @@ mod simplify {
                                     pos.func
                                         .dfg
                                         .replace(inst)
-                                        .BinaryImm64(opcode, ty, new_imm, new_arg);
+                                        .BinaryImm(opcode, ty, new_imm, new_arg);
                                     imm = new_imm;
                                     arg = new_arg;
                                 }
@@ -935,69 +935,6 @@ mod simplify {
                 }
             }
 
-            InstructionData::Ternary {
-                opcode: Opcode::Bitselect,
-                args,
-            } => {
-                let old_cond_type = pos.func.dfg.value_type(args[0]);
-                if !old_cond_type.is_vector() {
-                    return;
-                }
-
-                // Replace bitselect with vselect if each lane of controlling mask is either
-                // all ones or all zeroes; on x86 bitselect is encoded using 3 instructions,
-                // while vselect can be encoded using single BLEND instruction.
-                if let ValueDef::Result(def_inst, _) = pos.func.dfg.value_def(args[0]) {
-                    let (cond_val, cond_type) = match pos.func.dfg[def_inst] {
-                        InstructionData::Unary {
-                            opcode: Opcode::RawBitcast,
-                            arg,
-                        } => {
-                            // If controlling mask is raw-bitcasted boolean vector then
-                            // we know each lane is either all zeroes or ones,
-                            // so we can use vselect instruction instead.
-                            let arg_type = pos.func.dfg.value_type(arg);
-                            if !arg_type.is_vector() || !arg_type.lane_type().is_bool() {
-                                return;
-                            }
-                            (arg, arg_type)
-                        }
-                        InstructionData::UnaryConst {
-                            opcode: Opcode::Vconst,
-                            constant_handle,
-                        } => {
-                            // If each byte of controlling mask is 0x00 or 0xFF then
-                            // we will always bitcast our way to vselect(B8x16, I8x16, I8x16).
-                            // Bitselect operates at bit level, so the lane types don't matter.
-                            let const_data = pos.func.dfg.constants.get(constant_handle);
-                            if !const_data.iter().all(|&b| b == 0 || b == 0xFF) {
-                                return;
-                            }
-                            let new_type = B8.by(old_cond_type.bytes() as u16).unwrap();
-                            (pos.ins().raw_bitcast(new_type, args[0]), new_type)
-                        }
-                        _ => return,
-                    };
-
-                    let lane_type = Type::int(cond_type.lane_bits() as u16).unwrap();
-                    let arg_type = lane_type.by(cond_type.lane_count()).unwrap();
-                    let old_arg_type = pos.func.dfg.value_type(args[1]);
-
-                    if arg_type != old_arg_type {
-                        // Operands types must match, we need to add bitcasts.
-                        let arg1 = pos.ins().raw_bitcast(arg_type, args[1]);
-                        let arg2 = pos.ins().raw_bitcast(arg_type, args[2]);
-                        let ret = pos.ins().vselect(cond_val, arg1, arg2);
-                        pos.func.dfg.replace(inst).raw_bitcast(old_arg_type, ret);
-                    } else {
-                        pos.func
-                            .dfg
-                            .replace(inst)
-                            .vselect(cond_val, args[1], args[2]);
-                    }
-                }
-            }
-
             _ => {}
         }
     }
diff --git a/cranelift/codegen/src/verifier/mod.rs b/cranelift/codegen/src/verifier/mod.rs
index 00fc31e21..7f6953c7e 100644
--- a/cranelift/codegen/src/verifier/mod.rs
+++ b/cranelift/codegen/src/verifier/mod.rs
@@ -756,10 +756,10 @@ impl<'a> Verifier<'a> {
             | UnaryIeee64 { .. }
             | UnaryBool { .. }
             | Binary { .. }
-            | BinaryImm8 { .. }
-            | BinaryImm64 { .. }
+            | BinaryImm { .. }
             | Ternary { .. }
-            | TernaryImm8 { .. }
+            | InsertLane { .. }
+            | ExtractLane { .. }
             | Shuffle { .. }
             | IntCompare { .. }
             | IntCompareImm { .. }
@@ -1912,20 +1912,20 @@ impl<'a> Verifier<'a> {
                     Ok(())
                 }
             }
-            ir::InstructionData::BinaryImm8 {
+            ir::InstructionData::ExtractLane {
                 opcode: ir::instructions::Opcode::Extractlane,
-                imm: lane,
+                lane,
                 arg,
                 ..
             }
-            | ir::InstructionData::TernaryImm8 {
+            | ir::InstructionData::InsertLane {
                 opcode: ir::instructions::Opcode::Insertlane,
-                imm: lane,
+                lane,
                 args: [arg, _],
                 ..
             } => {
                 // We must be specific about the opcodes above because other instructions are using
-                // the same formats.
+                // the ExtractLane/InsertLane formats.
                 let ty = self.func.dfg.value_type(arg);
                 if u16::from(lane) >= ty.lane_count() {
                     errors.fatal((
diff --git a/cranelift/codegen/src/write.rs b/cranelift/codegen/src/write.rs
index ba4543d39..acf181af2 100644
--- a/cranelift/codegen/src/write.rs
+++ b/cranelift/codegen/src/write.rs
@@ -508,8 +508,7 @@ pub fn write_operands(
             constant_handle, ..
         } => write!(w, " {}", constant_handle),
         Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
-        BinaryImm8 { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
-        BinaryImm64 { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
+        BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
         Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
         MultiAry { ref args, .. } => {
             if args.is_empty() {
@@ -519,7 +518,8 @@ pub fn write_operands(
             }
         }
         NullAry { .. } => write!(w, " "),
-        TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm),
+        InsertLane { lane, args, .. } => write!(w, " {}, {}, {}", args[0], lane, args[1]),
+        ExtractLane { lane, arg, .. } => write!(w, " {}, {}", arg, lane),
         Shuffle { mask, args, .. } => {
             let data = dfg.immediates.get(mask).expect(
                 "Expected the shuffle mask to already be inserted into the immediates table",
diff --git a/cranelift/interpreter/src/interpreter.rs b/cranelift/interpreter/src/interpreter.rs
index 5485713d7..2790a78d7 100644
--- a/cranelift/interpreter/src/interpreter.rs
+++ b/cranelift/interpreter/src/interpreter.rs
@@ -11,8 +11,8 @@ use cranelift_codegen::ir::{
     Value as ValueRef, ValueList,
 };
 use cranelift_reader::{DataValue, DataValueCastFailure};
-use log::trace;
-use std::ops::{Add, Div, Mul, Sub};
+use log::debug;
+use std::ops::{Add, Sub};
 use thiserror::Error;
 
 /// The valid control flow states.
@@ -105,7 +105,7 @@ impl Interpreter {
 
     /// Interpret a call to a [Function] given its [DataValue] arguments.
     fn call(&self, function: &Function, arguments: &[DataValue]) -> Result<ControlFlow, Trap> {
-        trace!("Call: {}({:?})", function.name, arguments);
+        debug!("Call: {}({:?})", function.name, arguments);
         let first_block = function
             .layout
             .blocks()
@@ -117,20 +117,16 @@ impl Interpreter {
         self.block(&mut frame, first_block)
     }
 
-    /// Interpret a [Block] in a [Function]. This drives the interpretation over sequences of
-    /// instructions, which may continue in other blocks, until the function returns.
+    /// Interpret a single [Block] in a [Function].
     fn block(&self, frame: &mut Frame, block: Block) -> Result<ControlFlow, Trap> {
-        trace!("Block: {}", block);
-        let layout = &frame.function.layout;
-        let mut maybe_inst = layout.first_inst(block);
-        while let Some(inst) = maybe_inst {
+        debug!("Block: {}", block);
+        for inst in frame.function.layout.block_insts(block) {
             match self.inst(frame, inst)? {
-                ControlFlow::Continue => maybe_inst = layout.next_inst(inst),
+                ControlFlow::Continue => continue,
                 ControlFlow::ContinueAt(block, old_names) => {
-                    trace!("Block: {}", block);
                     let new_names = frame.function.dfg.block_params(block);
                     frame.rename(&old_names, new_names);
-                    maybe_inst = layout.first_inst(block)
+                    return self.block(frame, block);
                 }
                 ControlFlow::Return(rs) => return Ok(ControlFlow::Return(rs)),
             }
@@ -142,7 +138,7 @@ impl Interpreter {
     /// implementations.
     fn inst(&self, frame: &mut Frame, inst: Inst) -> Result<ControlFlow, Trap> {
         use ControlFlow::{Continue, ContinueAt};
-        trace!("Inst: {}", &frame.function.dfg.display_inst(inst, None));
+        debug!("Inst: {}", &frame.function.dfg.display_inst(inst, None));
 
         let data = &frame.function.dfg[inst];
         match data {
@@ -150,26 +146,20 @@ impl Interpreter {
                 let arg1 = frame.get(&args[0]);
                 let arg2 = frame.get(&args[1]);
                 let result = match opcode {
-                    Iadd => binary_op!(Add::add[arg1, arg2]; [I8, I16, I32, I64]; inst),
-                    Isub => binary_op!(Sub::sub[arg1, arg2]; [I8, I16, I32, I64]; inst),
-                    Imul => binary_op!(Mul::mul[arg1, arg2]; [I8, I16, I32, I64]; inst),
-                    Fadd => binary_op!(Add::add[arg1, arg2]; [F32, F64]; inst),
-                    Fsub => binary_op!(Sub::sub[arg1, arg2]; [F32, F64]; inst),
-                    Fmul => binary_op!(Mul::mul[arg1, arg2]; [F32, F64]; inst),
-                    Fdiv => binary_op!(Div::div[arg1, arg2]; [F32, F64]; inst),
+                    Iadd => binary_op!(Add::add[arg1, arg2]; [I8, I16, I32, I64, F32, F64]; inst),
+                    Isub => binary_op!(Sub::sub[arg1, arg2]; [I8, I16, I32, I64, F32, F64]; inst),
                     _ => unimplemented!("interpreter does not support opcode yet: {}", opcode),
                 }?;
                 frame.set(first_result(frame.function, inst), result);
                 Ok(Continue)
             }
 
-            BinaryImm64 { opcode, arg, imm } => {
+            BinaryImm { opcode, arg, imm } => {
                 let imm = DataValue::from_integer(*imm, type_of(*arg, frame.function))?;
                 let arg = frame.get(&arg);
                 let result = match opcode {
-                    IaddImm => binary_op!(Add::add[arg, imm]; [I8, I16, I32, I64]; inst),
-                    IrsubImm => binary_op!(Sub::sub[imm, arg]; [I8, I16, I32, I64]; inst),
-                    ImulImm => binary_op!(Mul::mul[arg, imm]; [I8, I16, I32, I64]; inst),
+                    IaddImm => binary_op!(Add::add[arg, imm]; [I8, I16, I32, I64, F32, F64]; inst),
+                    IrsubImm => binary_op!(Sub::sub[arg, imm]; [I8, I16, I32, I64, F32, F64]; inst),
                     _ => unimplemented!("interpreter does not support opcode yet: {}", opcode),
                 }?;
                 frame.set(first_result(frame.function, inst), result);
@@ -355,9 +345,9 @@ mod tests {
     fn sanity() {
         let code = "function %test() -> b1 {
         block0:
-            v0 = iconst.i32 1
-            v1 = iadd_imm v0, 1
-            v2 = irsub_imm v1, 44  ; 44 - 2 == 42 (see irsub_imm's semantics)
+            v0 = iconst.i32 40
+            v1 = iadd_imm v0, 3
+            v2 = irsub_imm v1, 1
             v3 = icmp_imm eq v2, 42
             return v3
         }";
diff --git a/cranelift/peepmatic/crates/macro/Cargo.toml b/cranelift/peepmatic/crates/macro/Cargo.toml
index 560953e0d..e13cffd98 100644
--- a/cranelift/peepmatic/crates/macro/Cargo.toml
+++ b/cranelift/peepmatic/crates/macro/Cargo.toml
@@ -13,5 +13,3 @@ syn = { version = "1.0.16", features = ['extra-traits'] }
 
 [lib]
 proc_macro = true
-test = false
-doctest = false
diff --git a/cranelift/reader/src/parser.rs b/cranelift/reader/src/parser.rs
index 55e44f41f..4a59a1366 100644
--- a/cranelift/reader/src/parser.rs
+++ b/cranelift/reader/src/parser.rs
@@ -1075,8 +1075,9 @@ impl<'a> Parser<'a> {
             if lane_size < 1 {
                 panic!("The boolean lane must have a byte size greater than zero.");
             }
-            let value = if value { 0xFF } else { 0 };
-            vec![value; lane_size as usize]
+            let mut buffer = vec![0; lane_size as usize];
+            buffer[0] = if value { 1 } else { 0 };
+            buffer
         }
 
         if !ty.is_vector() {
@@ -2752,17 +2753,11 @@ impl<'a> Parser<'a> {
                     args: [lhs, rhs],
                 }
             }
-            InstructionFormat::BinaryImm8 => {
-                let arg = self.match_value("expected SSA value first operand")?;
-                self.match_token(Token::Comma, "expected ',' between operands")?;
-                let imm = self.match_uimm8("expected unsigned 8-bit immediate")?;
-                InstructionData::BinaryImm8 { opcode, arg, imm }
-            }
-            InstructionFormat::BinaryImm64 => {
+            InstructionFormat::BinaryImm => {
                 let lhs = self.match_value("expected SSA value first operand")?;
                 self.match_token(Token::Comma, "expected ',' between operands")?;
                 let rhs = self.match_imm64("expected immediate integer second operand")?;
-                InstructionData::BinaryImm64 {
+                InstructionData::BinaryImm {
                     opcode,
                     arg: lhs,
                     imm: rhs,
@@ -2893,18 +2888,24 @@ impl<'a> Parser<'a> {
                 ctx.check_jt(table, self.loc)?;
                 InstructionData::IndirectJump { opcode, arg, table }
             }
-            InstructionFormat::TernaryImm8 => {
+            InstructionFormat::InsertLane => {
                 let lhs = self.match_value("expected SSA value first operand")?;
                 self.match_token(Token::Comma, "expected ',' between operands")?;
-                let rhs = self.match_value("expected SSA value last operand")?;
+                let lane = self.match_uimm8("expected lane number")?;
                 self.match_token(Token::Comma, "expected ',' between operands")?;
-                let imm = self.match_uimm8("expected 8-bit immediate")?;
-                InstructionData::TernaryImm8 {
+                let rhs = self.match_value("expected SSA value last operand")?;
+                InstructionData::InsertLane {
                     opcode,
-                    imm,
+                    lane,
                     args: [lhs, rhs],
                 }
             }
+            InstructionFormat::ExtractLane => {
+                let arg = self.match_value("expected SSA value last operand")?;
+                self.match_token(Token::Comma, "expected ',' between operands")?;
+                let lane = self.match_uimm8("expected lane number")?;
+                InstructionData::ExtractLane { opcode, lane, arg }
+            }
             InstructionFormat::Shuffle => {
                 let a = self.match_value("expected SSA value first operand")?;
                 self.match_token(Token::Comma, "expected ',' between operands")?;
@@ -3823,7 +3824,7 @@ mod tests {
             .unwrap();
         assert_eq!(
             c.into_vec(),
-            [0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0]
+            [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
         )
     }
 
diff --git a/cranelift/serde/src/serde_clif_json.rs b/cranelift/serde/src/serde_clif_json.rs
index 80ee84633..2d950cf3a 100644
--- a/cranelift/serde/src/serde_clif_json.rs
+++ b/cranelift/serde/src/serde_clif_json.rs
@@ -32,12 +32,7 @@ pub enum SerInstData {
         opcode: String,
         args: [String; 2],
     },
-    BinaryImm8 {
-        opcode: String,
-        arg: String,
-        imm: String,
-    },
-    BinaryImm64 {
+    BinaryImm {
         opcode: String,
         arg: String,
         imm: String,
@@ -46,11 +41,6 @@ pub enum SerInstData {
         opcode: String,
         args: [String; 3],
     },
-    TernaryImm8 {
-        opcode: String,
-        args: [String; 2],
-        imm: String,
-    },
     MultiAry {
         opcode: String,
         args: Vec<String>,
@@ -58,6 +48,16 @@ pub enum SerInstData {
     NullAry {
         opcode: String,
     },
+    InsertLane {
+        opcode: String,
+        args: [String; 2],
+        lane: String,
+    },
+    ExtractLane {
+        opcode: String,
+        arg: String,
+        lane: String,
+    },
     Shuffle {
         opcode: String,
         args: [String; 2],
@@ -292,12 +292,7 @@ pub fn get_inst_data(inst_index: Inst, func: &Function) -> SerInstData {
                 args: hold_args,
             }
         }
-        InstructionData::BinaryImm8 { opcode, arg, imm } => SerInstData::BinaryImm8 {
-            opcode: opcode.to_string(),
-            arg: arg.to_string(),
-            imm: imm.to_string(),
-        },
-        InstructionData::BinaryImm64 { opcode, arg, imm } => SerInstData::BinaryImm64 {
+        InstructionData::BinaryImm { opcode, arg, imm } => SerInstData::BinaryImm {
             opcode: opcode.to_string(),
             arg: arg.to_string(),
             imm: imm.to_string(),
@@ -328,14 +323,19 @@ pub fn get_inst_data(inst_index: Inst, func: &Function) -> SerInstData {
         InstructionData::NullAry { opcode } => SerInstData::NullAry {
             opcode: opcode.to_string(),
         },
-        InstructionData::TernaryImm8 { opcode, args, imm } => {
+        InstructionData::InsertLane { opcode, args, lane } => {
             let hold_args = [args[0].to_string(), args[1].to_string()];
-            SerInstData::TernaryImm8 {
+            SerInstData::InsertLane {
                 opcode: opcode.to_string(),
                 args: hold_args,
-                imm: imm.to_string(),
+                lane: lane.to_string(),
             }
         }
+        InstructionData::ExtractLane { opcode, arg, lane } => SerInstData::ExtractLane {
+            opcode: opcode.to_string(),
+            arg: arg.to_string(),
+            lane: lane.to_string(),
+        },
         InstructionData::UnaryConst {
             opcode,
             constant_handle,
diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs
index a8db0433b..6056d65f0 100644
--- a/cranelift/wasm/src/code_translator.rs
+++ b/cranelift/wasm/src/code_translator.rs
@@ -125,11 +125,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
                 GlobalVariable::Memory { gv, offset, ty } => {
                     let addr = builder.ins().global_value(environ.pointer_type(), gv);
                     let flags = ir::MemFlags::trusted();
-                    let mut val = state.pop1();
-                    // Ensure SIMD values are cast to their default Cranelift type, I8x16.
-                    if ty.is_vector() {
-                        val = optionally_bitcast_vector(val, I8X16, builder);
-                    }
+                    let val = state.pop1();
                     debug_assert_eq!(ty, builder.func.dfg.value_type(val));
                     builder.ins().store(flags, val, addr, offset);
                 }
@@ -1306,7 +1302,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
             let ty = type_of(op);
             let reduced = builder.ins().ireduce(ty.lane_type(), replacement);
             let vector = optionally_bitcast_vector(vector, ty, builder);
-            state.push1(builder.ins().insertlane(vector, reduced, *lane))
+            state.push1(builder.ins().insertlane(vector, *lane, reduced))
         }
         Operator::I32x4ReplaceLane { lane }
         | Operator::I64x2ReplaceLane { lane }
@@ -1314,7 +1310,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
         | Operator::F64x2ReplaceLane { lane } => {
             let (vector, replacement) = state.pop2();
             let vector = optionally_bitcast_vector(vector, type_of(op), builder);
-            state.push1(builder.ins().insertlane(vector, replacement, *lane))
+            state.push1(builder.ins().insertlane(vector, *lane, replacement))
         }
         Operator::V8x16Shuffle { lanes, .. } => {
             let (a, b) = pop2_with_bitcast(state, I8X16, builder);
diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h
index 1b43f9742..ec8ba8897 100644
--- a/crates/c-api/include/wasmtime.h
+++ b/crates/c-api/include/wasmtime.h
@@ -117,18 +117,6 @@ WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_instantiate(
     own wasm_trap_t **trap
 );
 
-WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_module(
-    const wasmtime_linker_t *linker,
-    const wasm_name_t *name,
-    const wasm_module_t *module
-);
-
-WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_get_default(
-    const wasmtime_linker_t *linker,
-    const wasm_name_t *name,
-    own wasm_func_t **func
-);
-
 ///////////////////////////////////////////////////////////////////////////////
 //
 // wasmtime_caller_t extension, binding the `Caller` type in the Rust API
diff --git a/crates/c-api/src/error.rs b/crates/c-api/src/error.rs
index cbb84873d..db0e25eae 100644
--- a/crates/c-api/src/error.rs
+++ b/crates/c-api/src/error.rs
@@ -10,8 +10,8 @@ pub struct wasmtime_error_t {
 wasmtime_c_api_macros::declare_own!(wasmtime_error_t);
 
 impl wasmtime_error_t {
-    pub(crate) fn to_trap(self) -> Box<wasm_trap_t> {
-        Box::new(wasm_trap_t::new(Trap::from(self.error)))
+    pub(crate) fn to_trap(&self) -> Box<wasm_trap_t> {
+        Box::new(wasm_trap_t::new(Trap::new(format!("{:?}", self.error))))
     }
 }
 
diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs
index 3578544ef..4faee0de8 100644
--- a/crates/c-api/src/linker.rs
+++ b/crates/c-api/src/linker.rs
@@ -1,8 +1,8 @@
 use crate::{bad_utf8, handle_result, wasmtime_error_t};
 use crate::{wasm_extern_t, wasm_store_t, ExternHost};
-use crate::{wasm_func_t, wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
+use crate::{wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
 use std::str;
-use wasmtime::{Extern, HostRef, Linker};
+use wasmtime::{Extern, Linker};
 
 #[repr(C)]
 pub struct wasmtime_linker_t {
@@ -89,33 +89,3 @@ pub unsafe extern "C" fn wasmtime_linker_instantiate(
     let result = linker.linker.instantiate(&module.module.borrow());
     super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
 }
-
-#[no_mangle]
-pub unsafe extern "C" fn wasmtime_linker_module(
-    linker: &mut wasmtime_linker_t,
-    name: &wasm_name_t,
-    module: &wasm_module_t,
-) -> Option<Box<wasmtime_error_t>> {
-    let linker = &mut linker.linker;
-    let name = match str::from_utf8(name.as_slice()) {
-        Ok(s) => s,
-        Err(_) => return bad_utf8(),
-    };
-    handle_result(linker.module(name, &module.module.borrow()), |_linker| ())
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn wasmtime_linker_get_default(
-    linker: &mut wasmtime_linker_t,
-    name: &wasm_name_t,
-    func: &mut *mut wasm_func_t,
-) -> Option<Box<wasmtime_error_t>> {
-    let linker = &mut linker.linker;
-    let name = match str::from_utf8(name.as_slice()) {
-        Ok(s) => s,
-        Err(_) => return bad_utf8(),
-    };
-    handle_result(linker.get_default(name), |f| {
-        *func = Box::into_raw(Box::new(HostRef::new(f).into()))
-    })
-}
diff --git a/crates/c-api/src/trap.rs b/crates/c-api/src/trap.rs
index 5f0cc2df9..8a93cba14 100644
--- a/crates/c-api/src/trap.rs
+++ b/crates/c-api/src/trap.rs
@@ -53,7 +53,7 @@ pub extern "C" fn wasm_trap_new(
 #[no_mangle]
 pub extern "C" fn wasm_trap_message(trap: &wasm_trap_t, out: &mut wasm_message_t) {
     let mut buffer = Vec::new();
-    buffer.extend_from_slice(trap.trap.borrow().to_string().as_bytes());
+    buffer.extend_from_slice(trap.trap.borrow().message().as_bytes());
     buffer.reserve_exact(1);
     buffer.push(0);
     out.set_buffer(buffer);
diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs
index 6c2f984c4..0e0550141 100644
--- a/crates/runtime/src/instance.rs
+++ b/crates/runtime/src/instance.rs
@@ -1330,4 +1330,8 @@ pub enum InstantiationError {
     /// A trap ocurred during instantiation, after linking.
     #[error("Trap occurred during instantiation")]
     Trap(Trap),
+
+    /// A trap occurred while running the wasm start function.
+    #[error("Trap occurred while invoking start function")]
+    StartTrap(Trap),
 }
diff --git a/crates/wasi-common/wig/src/wasi.rs b/crates/wasi-common/wig/src/wasi.rs
index 479cb2d86..579e6f3ca 100644
--- a/crates/wasi-common/wig/src/wasi.rs
+++ b/crates/wasi-common/wig/src/wasi.rs
@@ -209,7 +209,6 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
                             let memory = match caller.get_export("memory") {
                                 Some(wasmtime::Extern::Memory(m)) => m,
                                 _ => {
-                                    log::warn!("callee does not export a memory as \"memory\"");
                                     let e = wasi_common::old::snapshot_0::wasi::__WASI_ERRNO_INVAL;
                                     #handle_early_error
                                 }
@@ -464,7 +463,6 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
                             let mem = match caller.get_export("memory") {
                                 Some(wasmtime::Extern::Memory(m)) => m,
                                 _ => {
-                                    log::warn!("callee does not export a memory as \"memory\"");
                                     let e = wasi_common::wasi::Errno::Inval;
                                     #handle_early_error
                                 }
diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml
index 4334f72a6..84291e198 100644
--- a/crates/wasmtime/Cargo.toml
+++ b/crates/wasmtime/Cargo.toml
@@ -23,7 +23,6 @@ cfg-if = "0.1.9"
 backtrace = "0.3.42"
 rustc-demangle = "0.1.16"
 lazy_static = "1.4"
-log = "0.4.8"
 wat = { version = "1.0.18", optional = true }
 
 [target.'cfg(target_os = "windows")'.dependencies]
diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs
index eff5139b7..a048eecaf 100644
--- a/crates/wasmtime/src/instance.rs
+++ b/crates/wasmtime/src/instance.rs
@@ -26,25 +26,9 @@ fn instantiate(
     sig_registry: &SignatureRegistry,
     host: Box<dyn Any>,
 ) -> Result<StoreInstanceHandle, Error> {
-    // For now we have a restriction that the `Store` that we're working
-    // with is the same for everything involved here.
-    for import in imports {
-        if !import.comes_from_same_store(store) {
-            bail!("cross-`Store` instantiation is not currently supported");
-        }
-    }
-
-    if imports.len() != compiled_module.module().imports.len() {
-        bail!(
-            "wrong number of imports provided, {} != {}",
-            imports.len(),
-            compiled_module.module().imports.len()
-        );
-    }
-
     let mut resolver = SimpleResolver { imports };
-    let config = store.engine().config();
-    let instance = unsafe {
+    unsafe {
+        let config = store.engine().config();
         let instance = compiled_module.instantiate(
             &mut resolver,
             sig_registry,
@@ -67,38 +51,31 @@ fn instantiate(
             )
             .map_err(|e| -> Error {
                 match e {
-                    InstantiationError::Trap(trap) => Trap::from_runtime(trap).into(),
+                    InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
+                        Trap::from_runtime(trap).into()
+                    }
                     other => other.into(),
                 }
             })?;
 
-        instance
-    };
-
-    let start_func = instance.handle.module().start_func;
-
-    // If a start function is present, invoke it. Make sure we use all the
-    // trap-handling configuration in `store` as well.
-    if let Some(start) = start_func {
-        let f = match instance
-            .handle
-            .lookup_by_declaration(&EntityIndex::Function(start))
-        {
-            wasmtime_runtime::Export::Function(f) => f,
-            _ => unreachable!(), // valid modules shouldn't hit this
-        };
-        let vmctx_ptr = instance.handle.vmctx_ptr();
-        unsafe {
-            super::func::catch_traps(vmctx_ptr, store, || {
+        // If a start function is present, now that we've got our compiled
+        // instance we can invoke it. Make sure we use all the trap-handling
+        // configuration in `store` as well.
+        if let Some(start) = instance.module().start_func {
+            let f = match instance.lookup_by_declaration(&EntityIndex::Function(start)) {
+                wasmtime_runtime::Export::Function(f) => f,
+                _ => unreachable!(), // valid modules shouldn't hit this
+            };
+            super::func::catch_traps(instance.vmctx_ptr(), store, || {
                 mem::transmute::<
                     *const VMFunctionBody,
                     unsafe extern "C" fn(*mut VMContext, *mut VMContext),
-                >(f.address)(f.vmctx, vmctx_ptr)
+                >(f.address)(f.vmctx, instance.vmctx_ptr())
             })?;
         }
-    }
 
-    Ok(instance)
+        Ok(instance)
+    }
 }
 
 /// An instantiated WebAssembly module.
@@ -134,15 +111,6 @@ impl Instance {
     /// automatically run (if provided) and then the [`Instance`] will be
     /// returned.
     ///
-    /// Per the WebAssembly spec, instantiation includes running the module's
-    /// start function, if it has one (not to be confused with the `_start`
-    /// function, which is not run).
-    ///
-    /// Note that this is a low-level function that just performance an
-    /// instantiation. See the `Linker` struct for an API which provides a
-    /// convenient way to link imports and provides automatic Command and Reactor
-    /// behavior.
-    ///
     /// ## Providing Imports
     ///
     /// The `imports` array here is a bit tricky. The entries in the list of
@@ -179,6 +147,23 @@ impl Instance {
     /// [`ExternType`]: crate::ExternType
     pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
         let store = module.store();
+
+        // For now we have a restriction that the `Store` that we're working
+        // with is the same for everything involved here.
+        for import in imports {
+            if !import.comes_from_same_store(store) {
+                bail!("cross-`Store` instantiation is not currently supported");
+            }
+        }
+
+        if imports.len() != module.imports().len() {
+            bail!(
+                "wrong number of imports provided, {} != {}",
+                imports.len(),
+                module.imports().len()
+            );
+        }
+
         let info = module.register_frame_info();
         let handle = instantiate(
             store,
diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs
index 3a0682c18..888ad1cff 100644
--- a/crates/wasmtime/src/linker.rs
+++ b/crates/wasmtime/src/linker.rs
@@ -1,9 +1,7 @@
 use crate::{
     Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, Store,
-    Trap,
 };
-use anyhow::{anyhow, bail, Context, Error, Result};
-use log::warn;
+use anyhow::{anyhow, bail, Result};
 use std::collections::hash_map::{Entry, HashMap};
 use std::rc::Rc;
 
@@ -272,190 +270,6 @@ impl Linker {
         Ok(self)
     }
 
-    /// Define automatic instantiations of a [`Module`] in this linker.
-    ///
-    /// This automatically handles [Commands and Reactors] instantiation and
-    /// initialization.
-    ///
-    /// Exported functions of a Command module may be called directly, however
-    /// instead of having a single instance which is reused for each call,
-    /// each call creates a new instance, which lives for the duration of the
-    /// call. The imports of the Command are resolved once, and reused for
-    /// each instantiation, so all dependencies need to be present at the time
-    /// when `Linker::module` is called.
-    ///
-    /// For Reactors, a single instance is created, and an initialization
-    /// function is called, and then its exports may be called.
-    ///
-    /// Ordinary modules which don't declare themselves to be either Commands
-    /// or Reactors are treated as Reactors without any initialization calls.
-    ///
-    /// [Commands and Reactors]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi
-    ///
-    /// # Errors
-    ///
-    /// Returns an error if the any item is redefined twice in this linker (for
-    /// example the same `module_name` was already defined) and shadowing is
-    /// disallowed, if `instance` comes from a different [`Store`] than this
-    /// [`Linker`] originally was created with, or if a Reactor initialization
-    /// function traps.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use wasmtime::*;
-    /// # fn main() -> anyhow::Result<()> {
-    /// # let store = Store::default();
-    /// let mut linker = Linker::new(&store);
-    ///
-    /// // Instantiate a small instance and inform the linker that the name of
-    /// // this instance is `instance1`. This defines the `instance1::run` name
-    /// // for our next module to use.
-    /// let wat = r#"(module (func (export "run") ))"#;
-    /// let module = Module::new(&store, wat)?;
-    /// linker.module("instance1", &module)?;
-    ///
-    /// let wat = r#"
-    ///     (module
-    ///         (import "instance1" "run" (func $instance1_run))
-    ///         (func (export "run")
-    ///             call $instance1_run
-    ///         )
-    ///     )
-    /// "#;
-    /// let module = Module::new(&store, wat)?;
-    /// let instance = linker.instantiate(&module)?;
-    /// # Ok(())
-    /// # }
-    /// ```
-    ///
-    /// For a Command, a new instance is created for each call.
-    ///
-    /// ```
-    /// # use wasmtime::*;
-    /// # fn main() -> anyhow::Result<()> {
-    /// # let store = Store::default();
-    /// let mut linker = Linker::new(&store);
-    ///
-    /// // Create a Command that attempts to count the number of times it is run, but is
-    /// // foiled by each call getting a new instance.
-    /// let wat = r#"
-    ///     (module
-    ///         (global $counter (mut i32) (i32.const 0))
-    ///         (func (export "_start")
-    ///             (global.set $counter (i32.add (global.get $counter) (i32.const 1)))
-    ///         )
-    ///         (func (export "read_counter") (result i32)
-    ///             (global.get $counter)
-    ///         )
-    ///     )
-    /// "#;
-    /// let module = Module::new(&store, wat)?;
-    /// linker.module("commander", &module)?;
-    /// let run = linker.get_default("")?.get0::<()>()?;
-    /// run()?;
-    /// run()?;
-    /// run()?;
-    ///
-    /// let wat = r#"
-    ///     (module
-    ///         (import "commander" "_start" (func $commander_start))
-    ///         (import "commander" "read_counter" (func $commander_read_counter (result i32)))
-    ///         (func (export "run") (result i32)
-    ///             call $commander_start
-    ///             call $commander_start
-    ///             call $commander_start
-    ///             call $commander_read_counter
-    ///         )
-    ///     )
-    /// "#;
-    /// let module = Module::new(&store, wat)?;
-    /// linker.module("", &module)?;
-    /// let count = linker.get_one_by_name("", "run")?.into_func().unwrap().get0::<i32>()?()?;
-    /// assert_eq!(count, 0, "a Command should get a fresh instance on each invocation");
-    ///
-    /// # Ok(())
-    /// # }
-    /// ```
-    pub fn module(&mut self, module_name: &str, module: &Module) -> Result<&mut Self> {
-        match ModuleKind::categorize(module)? {
-            ModuleKind::Command => self.command(module_name, module),
-            ModuleKind::Reactor => {
-                let instance = self.instantiate(&module)?;
-
-                if let Some(export) = instance.get_export("_initialize") {
-                    if let Extern::Func(func) = export {
-                        func.get0::<()>()
-                            .and_then(|f| f().map_err(Into::into))
-                            .context("calling the Reactor initialization function")?;
-                    }
-                }
-
-                self.instance(module_name, &instance)
-            }
-        }
-    }
-
-    fn command(&mut self, module_name: &str, module: &Module) -> Result<&mut Self> {
-        for export in module.exports() {
-            if let Some(func_ty) = export.ty().func() {
-                let imports = self.compute_imports(module)?;
-                let module = module.clone();
-                let export_name = export.name().to_owned();
-                let func = Func::new(&self.store, func_ty.clone(), move |_, params, results| {
-                    // Create a new instance for this command execution.
-                    let instance = Instance::new(&module, &imports)?;
-
-                    // `unwrap()` everything here because we know the instance contains a
-                    // function export with the given name and signature because we're
-                    // iterating over the module it was instantiated from.
-                    let command_results = instance
-                        .get_export(&export_name)
-                        .unwrap()
-                        .into_func()
-                        .unwrap()
-                        .call(params)
-                        .map_err(|error| error.downcast::<Trap>().unwrap())?;
-
-                    // Copy the return values into the output slice.
-                    for (result, command_result) in
-                        results.iter_mut().zip(command_results.into_vec())
-                    {
-                        *result = command_result;
-                    }
-
-                    Ok(())
-                });
-                self.insert(module_name, export.name(), Extern::Func(func))?;
-            } else if export.name() == "memory" && export.ty().memory().is_some() {
-                // Allow an exported "memory" memory for now.
-            } else if export.name() == "__indirect_function_table" && export.ty().table().is_some()
-            {
-                // Allow an exported "__indirect_function_table" table for now.
-            } else if export.name() == "table" && export.ty().table().is_some() {
-                // Allow an exported "table" table for now.
-            } else if export.name() == "__data_end" && export.ty().global().is_some() {
-                // Allow an exported "__data_end" memory for compatibility with toolchains
-                // which use --export-dynamic, which unfortunately doesn't work the way
-                // we want it to.
-                warn!("command module exporting '__data_end' is deprecated");
-            } else if export.name() == "__heap_base" && export.ty().global().is_some() {
-                // Allow an exported "__data_end" memory for compatibility with toolchains
-                // which use --export-dynamic, which unfortunately doesn't work the way
-                // we want it to.
-                warn!("command module exporting '__heap_base' is deprecated");
-            } else if export.name() == "__rtti_base" && export.ty().global().is_some() {
-                // Allow an exported "__rtti_base" memory for compatibility with
-                // AssemblyScript.
-                warn!("command module exporting '__rtti_base' is deprecated; pass `--runtime half` to the AssemblyScript compiler");
-            } else {
-                bail!("command export '{}' is not a function", export.name());
-            }
-        }
-
-        Ok(self)
-    }
-
     /// Aliases one module's name as another.
     ///
     /// This method will alias all currently defined under `module` to also be
@@ -533,13 +347,9 @@ impl Linker {
     ///
     /// Each import of `module` will be looked up in this [`Linker`] and must
     /// have previously been defined. If it was previously defined with an
-    /// incorrect signature or if it was not previously defined then an error
+    /// incorrect signature or if it was not prevoiusly defined then an error
     /// will be returned because the import can not be satisfied.
     ///
-    /// Per the WebAssembly spec, instantiation includes running the module's
-    /// start function, if it has one (not to be confused with the `_start`
-    /// function, which is not run).
-    ///
     /// # Errors
     ///
     /// This method can fail because an import may not be found, or because
@@ -566,47 +376,44 @@ impl Linker {
     /// # }
     /// ```
     pub fn instantiate(&self, module: &Module) -> Result<Instance> {
-        let imports = self.compute_imports(module)?;
-
-        Instance::new(module, &imports)
-    }
-
-    fn compute_imports(&self, module: &Module) -> Result<Vec<Extern>> {
-        module
-            .imports()
-            .map(|import| self.get(&import).ok_or_else(|| self.link_error(&import)))
-            .collect()
-    }
-
-    fn link_error(&self, import: &ImportType) -> Error {
-        let mut options = Vec::new();
-        for i in self.map.keys() {
-            if &*self.strings[i.module] != import.module()
-                || &*self.strings[i.name] != import.name()
-            {
+        let mut imports = Vec::new();
+        for import in module.imports() {
+            if let Some(item) = self.get(&import) {
+                imports.push(item);
                 continue;
             }
-            options.push(format!("  * {:?}\n", i.kind));
-        }
-        if options.is_empty() {
-            return anyhow!(
-                "unknown import: `{}::{}` has not been defined",
-                import.module(),
-                import.name()
-            );
-        }
 
-        options.sort();
+            let mut options = String::new();
+            for i in self.map.keys() {
+                if &*self.strings[i.module] != import.module()
+                    || &*self.strings[i.name] != import.name()
+                {
+                    continue;
+                }
+                options.push_str("  * ");
+                options.push_str(&format!("{:?}", i.kind));
+                options.push_str("\n");
+            }
+            if options.len() == 0 {
+                bail!(
+                    "unknown import: `{}::{}` has not been defined",
+                    import.module(),
+                    import.name()
+                )
+            }
 
-        anyhow!(
-            "incompatible import type for `{}::{}` specified\n\
+            bail!(
+                "incompatible import type for `{}::{}` specified\n\
                  desired signature was: {:?}\n\
                  signatures available:\n\n{}",
-            import.module(),
-            import.name(),
-            import.ty(),
-            options.concat(),
-        )
+                import.module(),
+                import.name(),
+                import.ty(),
+                options,
+            )
+        }
+
+        Instance::new(module, &imports)
     }
 
     /// Returns the [`Store`] that this linker is connected to.
@@ -614,7 +421,7 @@ impl Linker {
         &self.store
     }
 
-    /// Returns an iterator over all items defined in this `Linker`, in arbitrary order.
+    /// Returns an iterator over all items defined in this `Linker`.
     ///
     /// The iterator returned will yield 3-tuples where the first two elements
     /// are the module name and item name for the external item, and the third
@@ -678,84 +485,4 @@ impl Linker {
         }
         Ok(ret.clone())
     }
-
-    /// Returns the "default export" of a module.
-    ///
-    /// An export with an empty string is considered to be a "default export".
-    /// "_start" is also recognized for compatibility.
-    pub fn get_default(&self, module: &str) -> Result<Func> {
-        let mut items = self.get_by_name(module, "");
-        if let Some(external) = items.next() {
-            if items.next().is_some() {
-                bail!("too many items named `` in `{}`", module);
-            }
-            if let Extern::Func(func) = external {
-                return Ok(func.clone());
-            }
-            bail!("default export in '{}' is not a function", module);
-        }
-
-        // For compatibility, also recognize "_start".
-        let mut items = self.get_by_name(module, "_start");
-        if let Some(external) = items.next() {
-            if items.next().is_some() {
-                bail!("too many items named `_start` in `{}`", module);
-            }
-            if let Extern::Func(func) = external {
-                return Ok(func.clone());
-            }
-            bail!("`_start` in '{}' is not a function", module);
-        }
-
-        // Otherwise return a no-op function.
-        Ok(Func::new(
-            &self.store,
-            FuncType::new(Vec::new().into_boxed_slice(), Vec::new().into_boxed_slice()),
-            move |_, _, _| Ok(()),
-        ))
-    }
-}
-
-/// Modules can be interpreted either as Commands or Reactors.
-enum ModuleKind {
-    /// The instance is a Command, meaning an instance is created for each
-    /// exported function and lives for the duration of the function call.
-    Command,
-
-    /// The instance is a Reactor, meaning one instance is created which
-    /// may live across multiple calls.
-    Reactor,
-}
-
-impl ModuleKind {
-    /// Determine whether the given module is a Command or a Reactor.
-    fn categorize(module: &Module) -> Result<ModuleKind> {
-        let command_start = module.get_export("_start");
-        let reactor_start = module.get_export("_initialize");
-        match (command_start, reactor_start) {
-            (Some(command_start), None) => {
-                if let Some(_) = command_start.func() {
-                    Ok(ModuleKind::Command)
-                } else {
-                    bail!("`_start` must be a function")
-                }
-            }
-            (None, Some(reactor_start)) => {
-                if let Some(_) = reactor_start.func() {
-                    Ok(ModuleKind::Reactor)
-                } else {
-                    bail!("`_initialize` must be a function")
-                }
-            }
-            (None, None) => {
-                // Module declares neither of the recognized functions, so treat
-                // it as a reactor with no initialization function.
-                Ok(ModuleKind::Reactor)
-            }
-            (Some(_), Some(_)) => {
-                // Module declares itself to be both a Command and a Reactor.
-                bail!("Program cannot be both a Command and a Reactor")
-            }
-        }
-    }
 }
diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs
index 102b0df82..c741d434e 100644
--- a/crates/wasmtime/src/module.rs
+++ b/crates/wasmtime/src/module.rs
@@ -1,6 +1,6 @@
 use crate::frame_info::GlobalFrameInfoRegistration;
 use crate::runtime::Store;
-use crate::types::{EntityType, ExportType, ExternType, ImportType};
+use crate::types::{EntityType, ExportType, ImportType};
 use anyhow::{Error, Result};
 use std::path::Path;
 use std::sync::{Arc, Mutex};
@@ -478,55 +478,6 @@ impl Module {
         })
     }
 
-    /// Looks up an export in this [`Module`] by name.
-    ///
-    /// This function will return the type of an export with the given name.
-    ///
-    /// # Examples
-    ///
-    /// There may be no export with that name:
-    ///
-    /// ```
-    /// # use wasmtime::*;
-    /// # fn main() -> anyhow::Result<()> {
-    /// # let store = Store::default();
-    /// let module = Module::new(&store, "(module)")?;
-    /// assert!(module.get_export("foo").is_none());
-    /// # Ok(())
-    /// # }
-    /// ```
-    ///
-    /// When there is an export with that name, it is returned:
-    ///
-    /// ```
-    /// # use wasmtime::*;
-    /// # fn main() -> anyhow::Result<()> {
-    /// # let store = Store::default();
-    /// let wat = r#"
-    ///     (module
-    ///         (func (export "foo"))
-    ///         (memory (export "memory") 1)
-    ///     )
-    /// "#;
-    /// let module = Module::new(&store, wat)?;
-    /// let foo = module.get_export("foo");
-    /// assert!(foo.is_some());
-    ///
-    /// let foo = foo.unwrap();
-    /// match foo {
-    ///     ExternType::Func(_) => { /* ... */ }
-    ///     _ => panic!("unexpected export type!"),
-    /// }
-    ///
-    /// # Ok(())
-    /// # }
-    /// ```
-    pub fn get_export<'module>(&'module self, name: &'module str) -> Option<ExternType> {
-        let module = self.inner.compiled.module_ref();
-        let entity_index = module.exports.get(name)?;
-        Some(EntityType::new(entity_index, module).extern_type())
-    }
-
     /// Returns the [`Store`] that this [`Module`] was compiled into.
     pub fn store(&self) -> &Store {
         &self.inner.store
diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs
index 03a7c349d..2ba9f2fc4 100644
--- a/crates/wasmtime/src/runtime.rs
+++ b/crates/wasmtime/src/runtime.rs
@@ -905,7 +905,7 @@ impl Store {
     /// });
     ///
     /// let trap = run().unwrap_err();
-    /// assert!(trap.to_string().contains("wasm trap: interrupt"));
+    /// assert!(trap.message().contains("wasm trap: interrupt"));
     /// # Ok(())
     /// # }
     /// ```
diff --git a/crates/wasmtime/src/trap.rs b/crates/wasmtime/src/trap.rs
index f8ec2acfa..4c160b4cf 100644
--- a/crates/wasmtime/src/trap.rs
+++ b/crates/wasmtime/src/trap.rs
@@ -20,9 +20,6 @@ enum TrapReason {
 
     /// An `i32` exit status describing an explicit program exit.
     I32Exit(i32),
-
-    /// A structured error describing a trap.
-    Error(Box<dyn std::error::Error + Send + Sync>),
 }
 
 impl fmt::Display for TrapReason {
@@ -30,7 +27,6 @@ impl fmt::Display for TrapReason {
         match self {
             TrapReason::Message(s) => write!(f, "{}", s),
             TrapReason::I32Exit(status) => write!(f, "Exited with i32 exit status {}", status),
-            TrapReason::Error(e) => write!(f, "{}", e),
         }
     }
 }
@@ -50,12 +46,11 @@ impl Trap {
     /// # Example
     /// ```
     /// let trap = wasmtime::Trap::new("unexpected error");
-    /// assert!(trap.to_string().contains("unexpected error"));
+    /// assert_eq!("unexpected error", trap.message());
     /// ```
     pub fn new<I: Into<String>>(message: I) -> Self {
         let info = FRAME_INFO.read().unwrap();
-        let reason = TrapReason::Message(message.into());
-        Trap::new_with_trace(&info, None, reason, Backtrace::new_unresolved())
+        Trap::new_with_trace(&info, None, message.into(), Backtrace::new_unresolved())
     }
 
     /// Creates a new `Trap` representing an explicit program exit with a classic `i32`
@@ -73,7 +68,19 @@ impl Trap {
     pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
         let info = FRAME_INFO.read().unwrap();
         match runtime_trap {
-            wasmtime_runtime::Trap::User(error) => Trap::from(error),
+            wasmtime_runtime::Trap::User(error) => {
+                // Since we're the only one using the wasmtime internals (in
+                // theory) we should only see user errors which were originally
+                // created from our own `Trap` type (see the trampoline module
+                // with functions).
+                //
+                // If this unwrap trips for someone we'll need to tweak the
+                // return type of this function to probably be `anyhow::Error`
+                // or something like that.
+                *error
+                    .downcast()
+                    .expect("only `Trap` user errors are supported")
+            }
             wasmtime_runtime::Trap::Jit {
                 pc,
                 backtrace,
@@ -93,8 +100,7 @@ impl Trap {
                 backtrace,
             } => Trap::new_wasm(&info, None, trap_code, backtrace),
             wasmtime_runtime::Trap::OOM { backtrace } => {
-                let reason = TrapReason::Message("out of memory".to_string());
-                Trap::new_with_trace(&info, None, reason, backtrace)
+                Trap::new_with_trace(&info, None, "out of memory".to_string(), backtrace)
             }
         }
     }
@@ -119,14 +125,14 @@ impl Trap {
             Interrupt => "interrupt",
             User(_) => unreachable!(),
         };
-        let msg = TrapReason::Message(format!("wasm trap: {}", desc));
+        let msg = format!("wasm trap: {}", desc);
         Trap::new_with_trace(info, trap_pc, msg, backtrace)
     }
 
     fn new_with_trace(
         info: &GlobalFrameInfo,
         trap_pc: Option<usize>,
-        reason: TrapReason,
+        message: String,
         native_trace: Backtrace,
     ) -> Self {
         let mut wasm_trace = Vec::new();
@@ -152,13 +158,24 @@ impl Trap {
         }
         Trap {
             inner: Arc::new(TrapInner {
-                reason,
+                reason: TrapReason::Message(message),
                 wasm_trace,
                 native_trace,
             }),
         }
     }
 
+    /// Returns a reference the `message` stored in `Trap`.
+    ///
+    /// In the case of an explicit exit, the exit status can be obtained by
+    /// calling `i32_exit_status`.
+    pub fn message(&self) -> &str {
+        match &self.inner.reason {
+            TrapReason::Message(message) => message,
+            TrapReason::I32Exit(_) => "explicitly exited",
+        }
+    }
+
     /// If the trap was the result of an explicit program exit with a classic
     /// `i32` exit status value, return the value, otherwise return `None`.
     pub fn i32_exit_status(&self) -> Option<i32> {
@@ -209,30 +226,4 @@ impl fmt::Display for Trap {
     }
 }
 
-impl std::error::Error for Trap {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match &self.inner.reason {
-            TrapReason::Error(e) => e.source(),
-            TrapReason::I32Exit(_) | TrapReason::Message(_) => None,
-        }
-    }
-}
-
-impl From<anyhow::Error> for Trap {
-    fn from(e: anyhow::Error) -> Trap {
-        Box::<dyn std::error::Error + Send + Sync>::from(e).into()
-    }
-}
-
-impl From<Box<dyn std::error::Error + Send + Sync>> for Trap {
-    fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Trap {
-        // If the top-level error is already a trap, don't be redundant and just return it.
-        if let Some(trap) = e.downcast_ref::<Trap>() {
-            trap.clone()
-        } else {
-            let info = FRAME_INFO.read().unwrap();
-            let reason = TrapReason::Error(e.into());
-            Trap::new_with_trace(&info, None, reason, Backtrace::new_unresolved())
-        }
-    }
-}
+impl std::error::Error for Trap {}
diff --git a/crates/wasmtime/src/types.rs b/crates/wasmtime/src/types.rs
index e03c6e41c..5fe37eeea 100644
--- a/crates/wasmtime/src/types.rs
+++ b/crates/wasmtime/src/types.rs
@@ -419,8 +419,7 @@ impl<'module> EntityType<'module> {
         }
     }
 
-    /// Convert this `EntityType` to an `ExternType`.
-    pub(crate) fn extern_type(&self) -> ExternType {
+    fn extern_type(&self) -> ExternType {
         match self {
             EntityType::Function(sig) => FuncType::from_wasmtime_signature(sig)
                 .expect("core wasm function type should be supported")
diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs
index 5574525da..5c3c22531 100644
--- a/crates/wast/src/wast.rs
+++ b/crates/wast/src/wast.rs
@@ -123,7 +123,7 @@ impl WastContext {
     fn module(&mut self, instance_name: Option<&str>, module: &[u8]) -> Result<()> {
         let instance = match self.instantiate(module)? {
             Outcome::Ok(i) => i,
-            Outcome::Trap(e) => return Err(e).context("instantiation failed"),
+            Outcome::Trap(e) => bail!("instantiation failed: {}", e.message()),
         };
         if let Some(name) = instance_name {
             self.linker.instance(name, &instance)?;
@@ -189,7 +189,7 @@ impl WastContext {
             Outcome::Ok(values) => bail!("expected trap, got {:?}", values),
             Outcome::Trap(t) => t,
         };
-        let actual = trap.to_string();
+        let actual = trap.message();
         if actual.contains(expected)
             // `bulk-memory-operations/bulk.wast` checks for a message that
             // specifies which element is uninitialized, but our traps don't
diff --git a/crates/wiggle/generate/src/config.rs b/crates/wiggle/generate/src/config.rs
index 0d4ada640..5f5fcb147 100644
--- a/crates/wiggle/generate/src/config.rs
+++ b/crates/wiggle/generate/src/config.rs
@@ -1,11 +1,15 @@
-use std::path::{Path, PathBuf};
-
-use proc_macro2::Span;
-use syn::{
-    braced, bracketed,
-    parse::{Parse, ParseStream},
-    punctuated::Punctuated,
-    Error, Ident, LitStr, Result, Token,
+use {
+    proc_macro2::Span,
+    std::{
+        iter::FromIterator,
+        path::{Path, PathBuf},
+    },
+    syn::{
+        braced, bracketed,
+        parse::{Parse, ParseStream},
+        punctuated::Punctuated,
+        Error, Ident, LitStr, Result, Token,
+    },
 };
 
 #[derive(Debug, Clone)]
@@ -23,7 +27,8 @@ pub enum ConfigField {
 impl ConfigField {
     pub fn parse_pair(ident: &str, value: ParseStream, err_loc: Span) -> Result<Self> {
         match ident {
-            "witx" => Ok(ConfigField::Witx(value.parse()?)),
+            "witx" => Ok(ConfigField::Witx(WitxConf::Paths(value.parse()?))),
+            "witx_literal" => Ok(ConfigField::Witx(WitxConf::Literal(value.parse()?))),
             "ctx" => Ok(ConfigField::Ctx(value.parse()?)),
             _ => Err(Error::new(err_loc, "expected `witx` or `ctx`")),
         }
@@ -61,6 +66,15 @@ impl Config {
                 .ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?,
         })
     }
+
+    /// Load the `witx` document for the configuration.
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if the paths given in the `witx` field were not valid documents.
+    pub fn load_document(&self) -> witx::Document {
+        self.witx.load_document()
+    }
 }
 
 impl Parse for Config {
@@ -73,31 +87,110 @@ impl Parse for Config {
     }
 }
 
+/// The witx document(s) that will be loaded from a [`Config`](struct.Config.html).
+///
+/// A witx interface definition can be provided either as a collection of relative paths to
+/// documents, or as a single inlined string literal. Note that `(use ...)` directives are not
+/// permitted when providing a string literal.
 #[derive(Debug, Clone)]
-pub struct WitxConf {
-    pub paths: Vec<PathBuf>,
+pub enum WitxConf {
+    /// A collection of paths pointing to witx files.
+    Paths(Paths),
+    /// A single witx document, provided as a string literal.
+    Literal(Literal),
 }
 
 impl WitxConf {
+    /// Load the `witx` document.
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if the paths given in the `witx` field were not valid documents, or
+    /// if any of the given documents were not syntactically valid.
+    pub fn load_document(&self) -> witx::Document {
+        match self {
+            Self::Paths(paths) => witx::load(paths.as_ref()).expect("loading witx"),
+            Self::Literal(doc) => witx::parse(doc.as_ref()).expect("parsing witx"),
+        }
+    }
+
+    /// If using the [`Paths`][paths] syntax, make all paths relative to a root directory.
+    ///
+    /// [paths]: enum.WitxConf.html#variant.Paths
     pub fn make_paths_relative_to<P: AsRef<Path>>(&mut self, root: P) {
-        self.paths.iter_mut().for_each(|p| {
-            if !p.is_absolute() {
-                *p = PathBuf::from(root.as_ref()).join(p.clone());
-            }
-        });
+        if let Self::Paths(paths) = self {
+            paths.as_mut().iter_mut().for_each(|p| {
+                if !p.is_absolute() {
+                    *p = PathBuf::from(root.as_ref()).join(p.clone());
+                }
+            });
+        }
+    }
+}
+
+/// A collection of paths, pointing to witx documents.
+#[derive(Debug, Clone)]
+pub struct Paths(Vec<PathBuf>);
+
+impl Paths {
+    /// Create a new, empty collection of paths.
+    pub fn new() -> Self {
+        Default::default()
+    }
+}
+
+impl Default for Paths {
+    fn default() -> Self {
+        Self(Default::default())
+    }
+}
+
+impl AsRef<[PathBuf]> for Paths {
+    fn as_ref(&self) -> &[PathBuf] {
+        self.0.as_ref()
+    }
+}
+
+impl AsMut<[PathBuf]> for Paths {
+    fn as_mut(&mut self) -> &mut [PathBuf] {
+        self.0.as_mut()
     }
 }
 
-impl Parse for WitxConf {
+impl FromIterator<PathBuf> for Paths {
+    fn from_iter<I>(iter: I) -> Self
+    where
+        I: IntoIterator<Item = PathBuf>,
+    {
+        Self(iter.into_iter().collect())
+    }
+}
+
+impl Parse for Paths {
     fn parse(input: ParseStream) -> Result<Self> {
         let content;
         let _ = bracketed!(content in input);
         let path_lits: Punctuated<LitStr, Token![,]> = content.parse_terminated(Parse::parse)?;
-        let paths = path_lits
+        Ok(path_lits
             .iter()
             .map(|lit| PathBuf::from(lit.value()))
-            .collect();
-        Ok(WitxConf { paths })
+            .collect())
+    }
+}
+
+/// A single witx document, provided as a string literal.
+#[derive(Debug, Clone)]
+pub struct Literal(String);
+
+impl AsRef<str> for Literal {
+    fn as_ref(&self) -> &str {
+        self.0.as_ref()
+    }
+}
+
+impl Parse for Literal {
+    fn parse(input: ParseStream) -> Result<Self> {
+        Ok(Self(input.parse::<syn::LitStr>()?.value()))
     }
 }
 
diff --git a/crates/wiggle/generate/src/names.rs b/crates/wiggle/generate/src/names.rs
index 644b877d8..84cbf5df7 100644
--- a/crates/wiggle/generate/src/names.rs
+++ b/crates/wiggle/generate/src/names.rs
@@ -1,10 +1,10 @@
-use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
+use crate::lifetimes::LifetimeExt;
+use escaping::{escape_id, handle_2big_enum_variant, NamingConvention};
+use heck::{ShoutySnakeCase, SnakeCase};
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
 use witx::{AtomType, BuiltinType, Id, Type, TypeRef};
 
-use crate::lifetimes::LifetimeExt;
-
 pub struct Names {
     ctx_type: Ident,
     runtime_mod: TokenStream,
@@ -17,16 +17,20 @@ impl Names {
             runtime_mod,
         }
     }
+
     pub fn ctx_type(&self) -> Ident {
         self.ctx_type.clone()
     }
+
     pub fn runtime_mod(&self) -> TokenStream {
         self.runtime_mod.clone()
     }
+
     pub fn type_(&self, id: &Id) -> TokenStream {
-        let ident = format_ident!("{}", id.as_str().to_camel_case());
+        let ident = escape_id(id, NamingConvention::CamelCase);
         quote!(#ident)
     }
+
     pub fn builtin_type(&self, b: BuiltinType, lifetime: TokenStream) -> TokenStream {
         match b {
             BuiltinType::String => {
@@ -83,15 +87,12 @@ impl Names {
         }
     }
 
+    /// Convert an enum variant from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn enum_variant(&self, id: &Id) -> Ident {
-        // FIXME this is a hack - just a proof of concept.
-        if id.as_str().starts_with('2') {
-            format_ident!("TooBig")
-        } else if id.as_str() == "type" {
-            format_ident!("Type")
-        } else {
-            format_ident!("{}", id.as_str().to_camel_case())
-        }
+        handle_2big_enum_variant(id).unwrap_or_else(|| escape_id(id, NamingConvention::CamelCase))
     }
 
     pub fn flag_member(&self, id: &Id) -> Ident {
@@ -102,34 +103,44 @@ impl Names {
         format_ident!("{}", id.as_str().to_shouty_snake_case())
     }
 
+    /// Convert a struct member from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn struct_member(&self, id: &Id) -> Ident {
-        // FIXME this is a hack - just a proof of concept.
-        if id.as_str() == "type" {
-            format_ident!("type_")
-        } else {
-            format_ident!("{}", id.as_str().to_snake_case())
-        }
+        escape_id(id, NamingConvention::SnakeCase)
     }
 
+    /// Convert a module name from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn module(&self, id: &Id) -> Ident {
-        format_ident!("{}", id.as_str().to_snake_case())
+        escape_id(id, NamingConvention::SnakeCase)
     }
 
+    /// Convert a trait name from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn trait_name(&self, id: &Id) -> Ident {
-        format_ident!("{}", id.as_str().to_camel_case())
+        escape_id(id, NamingConvention::CamelCase)
     }
 
+    /// Convert a function name from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn func(&self, id: &Id) -> Ident {
-        format_ident!("{}", id.as_str().to_snake_case())
+        escape_id(id, NamingConvention::SnakeCase)
     }
 
+    /// Convert a parameter name from its [`Id`][witx] name to its Rust [`Ident`][id] representation.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
     pub fn func_param(&self, id: &Id) -> Ident {
-        // FIXME this is a hack - just a proof of concept.
-        if id.as_str() == "in" {
-            format_ident!("in_")
-        } else {
-            format_ident!("{}", id.as_str().to_snake_case())
-        }
+        escape_id(id, NamingConvention::SnakeCase)
     }
 
     pub fn func_core_arg(&self, arg: &witx::CoreParamType) -> Ident {
@@ -174,3 +185,117 @@ impl Names {
         }
     }
 }
+
+/// Identifier escaping utilities.
+///
+/// This module most importantly exports an `escape_id` function that can be used to properly
+/// escape tokens that conflict with strict and reserved keywords, as of Rust's 2018 edition.
+///
+/// Weak keywords are not included as their semantic rules do not have the same implications as
+/// those of strict and reserved keywords. `union` for example, is permitted as the name of a
+/// variable. `dyn` was promoted to a strict keyword beginning in the 2018 edition.
+mod escaping {
+    use {
+        heck::{CamelCase, SnakeCase},
+        proc_macro2::Ident,
+        quote::format_ident,
+        witx::Id,
+    };
+
+    /// Identifier naming convention.
+    ///
+    /// Because shouty snake case values (identifiers that look `LIKE_THIS`) cannot potentially
+    /// conflict with any Rust keywords, this enum only include snake and camel case variants.
+    pub enum NamingConvention {
+        /// Snake case. Used to denote values `LikeThis`.
+        CamelCase,
+        /// Snake case. Used to denote values `like_this`.
+        SnakeCase,
+    }
+
+    /// Given a witx [`Id`][witx] and a [`NamingConvention`][naming], return a [`Ident`] word of
+    /// Rust syntax that accounts for escaping both strict and reserved keywords. If an identifier
+    /// would have conflicted with a keyword, a trailing underscode will be appended.
+    ///
+    /// [id]: https://docs.rs/proc-macro2/*/proc_macro2/struct.Ident.html
+    /// [naming]: enum.NamingConvention.html
+    /// [witx]: https://docs.rs/witx/*/witx/struct.Id.html
+    pub fn escape_id(id: &Id, conv: NamingConvention) -> Ident {
+        use NamingConvention::{CamelCase, SnakeCase};
+        match (conv, id.as_str()) {
+            // For camel-cased identifiers, `Self` is the only potential keyword conflict.
+            (CamelCase, "self") => format_ident!("Self_"),
+            (CamelCase, s) => format_ident!("{}", s.to_camel_case()),
+            // Snake-cased identifiers are where the bulk of conflicts can occur.
+            (SnakeCase, s) => {
+                let s = s.to_snake_case();
+                if STRICT.iter().chain(RESERVED).any(|k| *k == s) {
+                    // If the camel-cased string matched any strict or reserved keywords, then
+                    // append a trailing underscore to the identifier we generate.
+                    format_ident!("{}_", s)
+                } else {
+                    format_ident!("{}", s) // Otherwise, use the string as is.
+                }
+            }
+        }
+    }
+
+    /// Strict keywords.
+    ///
+    /// >  Strict keywords cannot be used as the names of:
+    /// >    * Items
+    /// >    * Variables and function parameters
+    /// >    * Fields and variants
+    /// >    * Type parameters
+    /// >    * Lifetime parameters or loop labels
+    /// >    * Macros or attributes
+    /// >    * Macro placeholders
+    /// >    * Crates
+    /// >
+    /// > - <cite>[The Rust Reference][ref]</cite>
+    ///
+    /// This list also includes keywords that were introduced in the 2018 edition of Rust.
+    ///
+    /// [ref]: https://doc.rust-lang.org/reference/keywords.html#strict-keywords
+    const STRICT: &[&str] = &[
+        "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum",
+        "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move",
+        "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait",
+        "true", "type", "unsafe", "use", "where", "while",
+    ];
+
+    /// Reserved keywords.
+    ///
+    /// > These keywords aren't used yet, but they are reserved for future use. They have the same
+    /// > restrictions as strict keywords. The reasoning behind this is to make current programs
+    /// > forward compatible with future versions of Rust by forbidding them to use these keywords.
+    /// >
+    /// > - <cite>[The Rust Reference][ref]</cite>
+    ///
+    /// This list also includes keywords that were introduced in the 2018 edition of Rust.
+    ///
+    /// [ref]: https://doc.rust-lang.org/reference/keywords.html#reserved-keywords
+    const RESERVED: &[&str] = &[
+        "abstract", "become", "box", "do", "final", "macro", "override", "priv", "try", "typeof",
+        "unsized", "virtual", "yield",
+    ];
+
+    /// Handle WASI's [`errno::2big`][err] variant.
+    ///
+    /// This is an unfortunate edge case that must account for when generating `enum` variants.
+    /// This will only return `Some(_)` if the given witx identifier *is* `2big`, otherwise this
+    /// function will return `None`.
+    ///
+    /// This functionality is a short-term fix that keeps WASI working. Instead of expanding these sort of special cases,
+    /// we should replace this function by having the user provide a mapping of witx identifiers to Rust identifiers in the
+    /// arguments to the macro.
+    ///
+    /// [err]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#-errno-enumu16
+    pub fn handle_2big_enum_variant(id: &Id) -> Option<Ident> {
+        if id.as_str() == "2big" {
+            Some(format_ident!("TooBig"))
+        } else {
+            None
+        }
+    }
+}
diff --git a/crates/wiggle/macro/src/lib.rs b/crates/wiggle/macro/src/lib.rs
index 8fd6f680a..7587a4245 100644
--- a/crates/wiggle/macro/src/lib.rs
+++ b/crates/wiggle/macro/src/lib.rs
@@ -95,7 +95,7 @@ pub fn from_witx(args: TokenStream) -> TokenStream {
         std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR env var"),
     );
 
-    let doc = witx::load(&config.witx.paths).expect("loading witx");
+    let doc = config.load_document();
     let names = wiggle_generate::Names::new(&config.ctx.name, quote!(wiggle));
 
     let code = wiggle_generate::generate(&doc, &names);
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 6409a86d9..f2cfcf34a 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -39,7 +39,6 @@
 - [Writing WebAssembly](./wasm.md)
   - [Rust](./wasm-rust.md)
   - [C/C++](./wasm-c.md)
-  - [AssemblyScript](./wasm-assemblyscript.md)
   - [WebAssembly Text Format (`*.wat`)](./wasm-wat.md)
   - [Example: Markdown Parser](./wasm-markdown.md)
 - [Stability](stability.md)
diff --git a/docs/assemblyscript-hello-world/package-lock.json b/docs/assemblyscript-hello-world/package-lock.json
deleted file mode 100644
index f4568e879..000000000
--- a/docs/assemblyscript-hello-world/package-lock.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "name": "wasi-hello-world",
-  "version": "1.0.0",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "as-wasi": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/as-wasi/-/as-wasi-0.1.1.tgz",
-      "integrity": "sha512-7PrSjsD/K2Pg95/2fu+4RJCfZLiuM0w0k5lMceaCf73EvH+7WPQTM1WW/vS0cizRTaEDj8Wz5ttoZBJSvsZpBQ=="
-    },
-    "assemblyscript": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.10.0.tgz",
-      "integrity": "sha512-ErUNhHboD+zsB4oG6X1YICDAIo27Gq7LeNX6jVe+Q0W5cI51/fHwC8yJ68IukqvupmZgYPdp1JqqRXlS+BrUfA==",
-      "dev": true,
-      "requires": {
-        "binaryen": "93.0.0-nightly.20200514",
-        "long": "^4.0.0"
-      }
-    },
-    "binaryen": {
-      "version": "93.0.0-nightly.20200514",
-      "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-93.0.0-nightly.20200514.tgz",
-      "integrity": "sha512-SRRItmNvhRVfoWWbRloO4i8IqkKH8rZ7/0QWRgLpM3umupK8gBpo9MY7Zp3pDysRSp+rVoqxvM5x4tFyCSa9zw==",
-      "dev": true
-    },
-    "long": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
-      "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
-      "dev": true
-    }
-  }
-}
diff --git a/docs/assemblyscript-hello-world/package.json b/docs/assemblyscript-hello-world/package.json
deleted file mode 100644
index 2bcd9100a..000000000
--- a/docs/assemblyscript-hello-world/package.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "name": "wasi-hello-world",
-  "version": "1.0.0",
-  "description": "Hello world in Wasi with AS and as-wasi",
-  "main": "index.js",
-  "scripts": {
-    "build": "asc wasi-hello-world.ts -b wasi-hello-world.wasm -t wasi-hello-world.wat --runtime half",
-    "wasmtime": "wasmtime wasi-hello-world.wasm"
-  },
-  "author": "Aaron Turner",
-  "license": "MIT",
-  "devDependencies": {
-    "assemblyscript": "^0.10.0"
-  },
-  "dependencies": {
-    "as-wasi": "^0.1.1"
-  }
-}
diff --git a/docs/assemblyscript-hello-world/wasi-hello-world.ts b/docs/assemblyscript-hello-world/wasi-hello-world.ts
deleted file mode 100644
index 1cd3065fe..000000000
--- a/docs/assemblyscript-hello-world/wasi-hello-world.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import "wasi"
-
-import {Console} from "as-wasi"
-Console.log('Hello World!\n');
-
diff --git a/docs/wasm-assemblyscript.md b/docs/wasm-assemblyscript.md
deleted file mode 100644
index fddd9bd74..000000000
--- a/docs/wasm-assemblyscript.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# AssemblyScript
-
-[AssemblyScript] 0.10.0 includes support for targeting WASI. To use it, add
-`import "wasi"` at the top of your entrypoint file.
-
-To create a program which can be run directly as a command, pass `--runtime half`
-to the AssemblyScript linker. This selects the [half runtime], which ensures that
-the generated wasm module doesn't contain any extraneous exports. (This isn't
-strictly required today, but the handling of extraneous exports may change in
-the future, so it's encouraged. As a bonus, it also reduces code size.)
-
-To create a program which can be loaded as a library and used from other modules,
-no special options are needed.
-
-Let's walk through a simple hello world example.
-
-## `wasi-hello-world.ts`
-
-```typescript
-{{#include ./assemblyscript-hello-world/wasi-hello-world.ts}}
-```
-
-This uses [as-wasi] as a dependency to make working with the AssemblyScript WASI
-bindings easier. Then, you can run:
-
-```sh
-asc wasi-hello-world.ts -b wasi-hello-world.wasm
-```
-
-to compile it to wasm, and
-
-```sh
-wasmtime wasi-hello-world.wasm
-```
-
-to run it from the command-line. Or you can instantiate it using the [Wasmtime API].
-
-## `package.json`
-
-It can also be packaged using a `package.json` file:
-
-```json
-{{#include ./assemblyscript-hello-world/package.json}}
-```
-
-You can also [browse this source code online][code] and clone the wasmtime
-repository to run the example locally.
-
-[code]: https://github.com/bytecodealliance/wasmtime/blob/master/docs/assemblyscript-hello-world
-[AssemblyScript]: https://assemblyscript.org
-[as-wasi]: https://github.com/jedisct1/as-wasi
-[half runtime]: https://docs.assemblyscript.org/details/runtime#runtime-variants
-[Wasmtime API]: ./lang.md
diff --git a/docs/wasm.md b/docs/wasm.md
index fb442f600..b524cc811 100644
--- a/docs/wasm.md
+++ b/docs/wasm.md
@@ -9,5 +9,4 @@ check out your language's documentation for WebAssembly as well.
 
 * [Rust](wasm-rust.md)
 * [C/C++](wasm-c.md)
-* [AssemblyScript](wasm-assemblyscript.md)
 * [WebAssembly Text Format (`*.wat`)](wasm-wat.md)
diff --git a/examples/interrupt.rs b/examples/interrupt.rs
index 6a42867cc..696d8a2d9 100644
--- a/examples/interrupt.rs
+++ b/examples/interrupt.rs
@@ -32,7 +32,7 @@ fn main() -> Result<()> {
     let trap = run().unwrap_err();
 
     println!("trap received...");
-    assert!(trap.to_string().contains("wasm trap: interrupt"));
+    assert!(trap.message().contains("wasm trap: interrupt"));
 
     Ok(())
 }
diff --git a/examples/wasi/main.c b/examples/wasi/main.c
index 68a978ccd..1226f94ce 100644
--- a/examples/wasi/main.c
+++ b/examples/wasi/main.c
@@ -72,30 +72,51 @@ int main() {
   if (wasi == NULL)
     exit_with_error("failed to instantiate WASI", NULL, trap);
 
-  wasmtime_linker_t *linker = wasmtime_linker_new(store);
-  error = wasmtime_linker_define_wasi(linker, wasi);
-  if (error != NULL)
-    exit_with_error("failed to link wasi", error, NULL);
+  // Create import list for our module using wasi
+  wasm_importtype_vec_t import_types;
+  wasm_module_imports(module, &import_types);
+  const wasm_extern_t **imports = calloc(import_types.size, sizeof(void*));
+  assert(imports);
+  for (int i = 0; i < import_types.size; i++) {
+    const wasm_extern_t *binding = wasi_instance_bind_import(wasi, import_types.data[i]);
+    if (binding != NULL) {
+      imports[i] = binding;
+    } else {
+      printf("> Failed to satisfy import\n");
+      exit(1);
+    }
+  }
 
   // Instantiate the module
-  wasm_name_t empty;
-  wasm_name_new_from_string(&empty, "");
   wasm_instance_t *instance = NULL;
-  error = wasmtime_linker_module(linker, &empty, module);
-  if (error != NULL)
-    exit_with_error("failed to instantiate module", error, NULL);
+  error = wasmtime_instance_new(module, imports, import_types.size, &instance, &trap);
+  if (instance == NULL)
+    exit_with_error("failed to instantiate", error, trap);
+  free(imports);
+  wasm_importtype_vec_delete(&import_types);
 
-  // Run it.
-  wasm_func_t* func;
-  wasmtime_linker_get_default(linker, &empty, &func);
-  if (error != NULL)
-    exit_with_error("failed to locate default export for module", error, NULL);
-  error = wasmtime_func_call(func, NULL, 0, NULL, 0, &trap);
-  if (error != NULL)
-    exit_with_error("error calling default export", error, trap);
+  // Lookup our `_start` export function
+  wasm_extern_vec_t externs;
+  wasm_instance_exports(instance, &externs);
+  wasm_exporttype_vec_t exports;
+  wasm_module_exports(module, &exports);
+  wasm_extern_t *start_extern = NULL;
+  for (int i = 0; i < exports.size; i++) {
+    const wasm_name_t *name = wasm_exporttype_name(exports.data[i]);
+    if (strncmp(name->data, "_start", name->size) == 0)
+      start_extern = externs.data[i];
+  }
+  assert(start_extern);
+  wasm_func_t *start = wasm_extern_as_func(start_extern);
+  assert(start != NULL);
+  error = wasmtime_func_call(start, NULL, 0, NULL, 0, &trap);
+  if (error != NULL || trap != NULL)
+    exit_with_error("failed to call `_start`", error, trap);
 
   // Clean up after ourselves at this point
-  wasm_name_delete(&empty);
+  wasm_exporttype_vec_delete(&exports);
+  wasm_extern_vec_delete(&externs);
+  wasm_instance_delete(instance);
   wasm_module_delete(module);
   wasm_store_delete(store);
   wasm_engine_delete(engine);
diff --git a/examples/wasi/main.rs b/examples/wasi/main.rs
index c663e9527..8971364cd 100644
--- a/examples/wasi/main.rs
+++ b/examples/wasi/main.rs
@@ -9,18 +9,32 @@ use wasmtime_wasi::{Wasi, WasiCtx};
 
 fn main() -> Result<()> {
     let store = Store::default();
-    let mut linker = Linker::new(&store);
+    let module = Module::from_file(&store, "target/wasm32-wasi/debug/wasi.wasm")?;
 
     // Create an instance of `Wasi` which contains a `WasiCtx`. Note that
     // `WasiCtx` provides a number of ways to configure what the target program
     // will have access to.
     let wasi = Wasi::new(&store, WasiCtx::new(std::env::args())?);
-    wasi.add_to_linker(&mut linker)?;
-
-    // Instantiate our module with the imports we've created, and run it.
-    let module = Module::from_file(&store, "target/wasm32-wasi/debug/wasi.wasm")?;
-    linker.module("", &module)?;
-    linker.get_default("")?.get0::<()>()?()?;
+    let mut imports = Vec::new();
+    for import in module.imports() {
+        if import.module() == "wasi_snapshot_preview1" {
+            if let Some(export) = wasi.get_export(import.name()) {
+                imports.push(Extern::from(export.clone()));
+                continue;
+            }
+        }
+        panic!(
+            "couldn't find import for `{}::{}`",
+            import.module(),
+            import.name()
+        );
+    }
 
+    // Instance our module with the imports we've created, then we can run the
+    // standard wasi `_start` function.
+    let instance = Instance::new(&module, &imports)?;
+    let start = instance.get_func("_start").unwrap();
+    let start = start.get0::<()>()?;
+    start()?;
     Ok(())
 }
diff --git a/src/commands/run.rs b/src/commands/run.rs
index 4e40d057f..e638606b8 100644
--- a/src/commands/run.rs
+++ b/src/commands/run.rs
@@ -7,13 +7,13 @@ use std::time::Duration;
 use std::{
     ffi::{OsStr, OsString},
     fs::File,
-    path::{Component, PathBuf},
+    path::{Component, Path, PathBuf},
     process,
 };
 use structopt::{clap::AppSettings, StructOpt};
-use wasi_common::{preopen_dir, WasiCtxBuilder};
-use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType};
-use wasmtime_wasi::Wasi;
+use wasi_common::preopen_dir;
+use wasmtime::{Engine, Instance, Module, Store, Trap, Val, ValType};
+use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi};
 
 fn parse_module(s: &OsStr) -> Result<PathBuf, OsString> {
     // Do not accept wasmtime subcommand names as the module name
@@ -51,14 +51,6 @@ fn parse_dur(s: &str) -> Result<Duration> {
     Ok(dur)
 }
 
-fn parse_preloads(s: &str) -> Result<(String, PathBuf)> {
-    let parts: Vec<&str> = s.splitn(2, '=').collect();
-    if parts.len() != 2 {
-        bail!("must contain exactly one equals character ('=')");
-    }
-    Ok((parts[0].into(), parts[1].into()))
-}
-
 /// Runs a WebAssembly module
 #[derive(StructOpt)]
 #[structopt(name = "run", setting = AppSettings::TrailingVarArg)]
@@ -95,10 +87,10 @@ pub struct RunCommand {
     #[structopt(
         long = "preload",
         number_of_values = 1,
-        value_name = "NAME=MODULE_PATH",
-        parse(try_from_str = parse_preloads)
+        value_name = "MODULE_PATH",
+        parse(from_os_str)
     )]
-    preloads: Vec<(String, PathBuf)>,
+    preloads: Vec<PathBuf>,
 
     /// Maximum execution time of wasm code before timing out (1, 2s, 100ms, etc)
     #[structopt(
@@ -135,25 +127,17 @@ impl RunCommand {
         let preopen_dirs = self.compute_preopen_dirs()?;
         let argv = self.compute_argv();
 
-        let mut linker = Linker::new(&store);
-        populate_with_wasi(&mut linker, &preopen_dirs, &argv, &self.vars)?;
+        let module_registry = ModuleRegistry::new(&store, &preopen_dirs, &argv, &self.vars)?;
 
         // Load the preload wasm modules.
-        for (name, path) in self.preloads.iter() {
-            // Read the wasm module binary either as `*.wat` or a raw binary
-            let module = Module::from_file(linker.store(), path)?;
-
-            // Add the module's functions to the linker.
-            linker.module(name, &module).context(format!(
-                "failed to process preload `{}` at `{}`",
-                name,
-                path.display()
-            ))?;
+        for preload in self.preloads.iter() {
+            Self::instantiate_module(&store, &module_registry, preload)
+                .with_context(|| format!("failed to process preload at `{}`", preload.display()))?;
         }
 
         // Load the main wasm module.
         match self
-            .load_main_module(&mut linker)
+            .handle_module(&store, &module_registry)
             .with_context(|| format!("failed to run main module `{}`", self.module.display()))
         {
             Ok(()) => (),
@@ -162,6 +146,8 @@ impl RunCommand {
                 // a message and exit.
                 if let Some(trap) = e.downcast_ref::<Trap>() {
                     // Print the error message in the usual way.
+                    eprintln!("Error: {:?}", e);
+
                     if let Some(status) = trap.i32_exit_status() {
                         // On Windows, exit status 3 indicates an abort (see below),
                         // so return 1 indicating a non-zero status to avoid ambiguity.
@@ -171,8 +157,6 @@ impl RunCommand {
                         process::exit(status);
                     }
 
-                    eprintln!("Error: {:?}", e);
-
                     // If the program exited because of a trap, return an error code
                     // to the outside environment indicating a more severe problem
                     // than a simple failure.
@@ -236,40 +220,79 @@ impl RunCommand {
         result
     }
 
-    fn load_main_module(&self, linker: &mut Linker) -> Result<()> {
+    fn instantiate_module(
+        store: &Store,
+        module_registry: &ModuleRegistry,
+        path: &Path,
+    ) -> Result<Instance> {
+        // Read the wasm module binary either as `*.wat` or a raw binary
+        let data = wat::parse_file(path)?;
+
+        let module = Module::new(store, &data)?;
+
+        // Resolve import using module_registry.
+        let imports = module
+            .imports()
+            .map(|i| {
+                let export = match i.module() {
+                    "wasi_snapshot_preview1" => {
+                        module_registry.wasi_snapshot_preview1.get_export(i.name())
+                    }
+                    "wasi_unstable" => module_registry.wasi_unstable.get_export(i.name()),
+                    other => bail!("import module `{}` was not found", other),
+                };
+                match export {
+                    Some(export) => Ok(export.clone().into()),
+                    None => bail!(
+                        "import `{}` was not found in module `{}`",
+                        i.name(),
+                        i.module()
+                    ),
+                }
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        let instance = Instance::new(&module, &imports)
+            .context(format!("failed to instantiate {:?}", path))?;
+
+        Ok(instance)
+    }
+
+    fn handle_module(&self, store: &Store, module_registry: &ModuleRegistry) -> Result<()> {
         if let Some(timeout) = self.wasm_timeout {
-            let handle = linker.store().interrupt_handle()?;
+            let handle = store.interrupt_handle()?;
             thread::spawn(move || {
                 thread::sleep(timeout);
                 handle.interrupt();
             });
         }
-
-        // Read the wasm module binary either as `*.wat` or a raw binary.
-        // Use "" as a default module name.
-        let module = Module::from_file(linker.store(), &self.module)?;
-        linker
-            .module("", &module)
-            .context(format!("failed to instantiate {:?}", self.module))?;
+        let instance = Self::instantiate_module(store, module_registry, &self.module)?;
 
         // If a function to invoke was given, invoke it.
         if let Some(name) = self.invoke.as_ref() {
-            self.invoke_export(linker, name)
+            self.invoke_export(instance, name)?;
+        } else if instance.exports().any(|export| export.name().is_empty()) {
+            // Launch the default command export.
+            self.invoke_export(instance, "")?;
         } else {
-            let func = linker.get_default("")?;
-            self.invoke_func(func, None)
+            // If the module doesn't have a default command export, launch the
+            // _start function if one is present, as a compatibility measure.
+            self.invoke_export(instance, "_start")?;
         }
-    }
 
-    fn invoke_export(&self, linker: &Linker, name: &str) -> Result<()> {
-        let func = match linker.get_one_by_name("", name)?.into_func() {
-            Some(func) => func,
-            None => bail!("export of `{}` wasn't a function", name),
-        };
-        self.invoke_func(func, Some(name))
+        Ok(())
     }
 
-    fn invoke_func(&self, func: Func, name: Option<&str>) -> Result<()> {
+    fn invoke_export(&self, instance: Instance, name: &str) -> Result<()> {
+        let func = if let Some(export) = instance.get_export(name) {
+            if let Some(func) = export.into_func() {
+                func
+            } else {
+                bail!("export of `{}` wasn't a function", name)
+            }
+        } else {
+            bail!("failed to find export of `{}` in module", name)
+        };
         let ty = func.ty();
         if ty.params().len() > 0 {
             eprintln!(
@@ -282,13 +305,7 @@ impl RunCommand {
         for ty in ty.params() {
             let val = match args.next() {
                 Some(s) => s,
-                None => {
-                    if let Some(name) = name {
-                        bail!("not enough arguments for `{}`", name)
-                    } else {
-                        bail!("not enough arguments for command default")
-                    }
-                }
+                None => bail!("not enough arguments for `{}`", name),
             };
             values.push(match ty {
                 // TODO: integer parsing here should handle hexadecimal notation
@@ -304,13 +321,9 @@ impl RunCommand {
 
         // Invoke the function and then afterwards print all the results that came
         // out, if there are any.
-        let results = func.call(&values).with_context(|| {
-            if let Some(name) = name {
-                format!("failed to invoke `{}`", name)
-            } else {
-                format!("failed to invoke command default")
-            }
-        })?;
+        let results = func
+            .call(&values)
+            .with_context(|| format!("failed to invoke `{}`", name))?;
         if !results.is_empty() {
             eprintln!(
                 "warning: using `--invoke` with a function that returns values \
@@ -334,36 +347,41 @@ impl RunCommand {
     }
 }
 
-/// Populates the given `Linker` with WASI APIs.
-fn populate_with_wasi(
-    linker: &mut Linker,
-    preopen_dirs: &[(String, File)],
-    argv: &[String],
-    vars: &[(String, String)],
-) -> Result<()> {
-    // Add the current snapshot to the linker.
-    let mut cx = WasiCtxBuilder::new();
-    cx.inherit_stdio().args(argv).envs(vars);
-
-    for (name, file) in preopen_dirs {
-        cx.preopened_dir(file.try_clone()?, name);
-    }
+struct ModuleRegistry {
+    wasi_snapshot_preview1: Wasi,
+    wasi_unstable: WasiSnapshot0,
+}
 
-    let cx = cx.build()?;
-    let wasi = Wasi::new(linker.store(), cx);
-    wasi.add_to_linker(linker)?;
+impl ModuleRegistry {
+    fn new(
+        store: &Store,
+        preopen_dirs: &[(String, File)],
+        argv: &[String],
+        vars: &[(String, String)],
+    ) -> Result<ModuleRegistry> {
+        let mut cx1 = wasi_common::WasiCtxBuilder::new();
 
-    // Repeat the above, but this time for snapshot 0.
-    let mut cx = wasi_common::old::snapshot_0::WasiCtxBuilder::new();
-    cx.inherit_stdio().args(argv).envs(vars);
+        cx1.inherit_stdio().args(argv).envs(vars);
 
-    for (name, file) in preopen_dirs {
-        cx.preopened_dir(file.try_clone()?, name);
-    }
+        for (name, file) in preopen_dirs {
+            cx1.preopened_dir(file.try_clone()?, name);
+        }
+
+        let cx1 = cx1.build()?;
+
+        let mut cx2 = wasi_common::old::snapshot_0::WasiCtxBuilder::new();
 
-    let cx = cx.build()?;
-    let wasi = wasmtime_wasi::old::snapshot_0::Wasi::new(linker.store(), cx);
-    wasi.add_to_linker(linker)?;
+        cx2.inherit_stdio().args(argv).envs(vars);
 
-    Ok(())
+        for (name, file) in preopen_dirs {
+            cx2.preopened_dir(file.try_clone()?, name);
+        }
+
+        let cx2 = cx2.build()?;
+
+        Ok(ModuleRegistry {
+            wasi_snapshot_preview1: Wasi::new(store, cx1),
+            wasi_unstable: WasiSnapshot0::new(store, cx2),
+        })
+    }
 }


Test patch:
diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
index 1dd6be20e..b948f4fd8 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
@@ -2164,15 +2164,6 @@ fn test_aarch64_binemit() {
         "mov v8.8b, v4.8b",
     ));
 
-    insns.push((
-        Inst::FpuMove128 {
-            rd: writable_vreg(17),
-            rn: vreg(26),
-        },
-        "511FBA4E",
-        "mov v17.16b, v26.16b",
-    ));
-
     insns.push((
         Inst::FpuRR {
             fpu_op: FPUOp1::Abs32,
@@ -2735,15 +2726,6 @@ fn test_aarch64_binemit() {
         "ldr d16, pc+8 ; b 12 ; data.f64 1",
     ));
 
-    insns.push((
-        Inst::LoadFpuConst128 {
-            rd: writable_vreg(5),
-            const_data: 0x0f0e0d0c0b0a09080706050403020100,
-        },
-        "4500009C05000014000102030405060708090A0B0C0D0E0F",
-        "ldr q5, pc+8 ; b 20 ; data.f128 0x0f0e0d0c0b0a09080706050403020100",
-    ));
-
     insns.push((
         Inst::FpuCSel32 {
             rd: writable_vreg(1),
diff --git a/cranelift/filetests/filetests/interpreter/fibonacci.clif b/cranelift/filetests/filetests/interpreter/fibonacci.clif
index bdce284f3..70515c4b2 100644
--- a/cranelift/filetests/filetests/interpreter/fibonacci.clif
+++ b/cranelift/filetests/filetests/interpreter/fibonacci.clif
@@ -10,12 +10,12 @@ block0(v0: i32):
 
 block1(v4: i32, v5:i32):
     v6 = iconst.i32 1
-    v7 = iadd_imm v4, -2
+    v7 = irsub_imm v4, 2
     fallthrough block2(v7, v5, v6)
 
 block2(v10: i32, v11: i32, v12: i32): ; params: n, fib(n-1), fib(n-2)
     v13 = iadd v11, v12
-    v14 = iadd_imm v10, -1
+    v14 = irsub_imm v10, 1
     v15 = icmp_imm eq v14, 0
     brnz v15, block3(v13)
     jump block2(v14, v13, v11)
@@ -43,9 +43,9 @@ block0(v0: i32):
     fallthrough block1(v0)
 
 block1(v10: i32):
-    v11 = iadd_imm v10, -1
+    v11 = irsub_imm v10, 1
     v12 = call fn0(v11)
-    v13 = iadd_imm v10, -2
+    v13 = irsub_imm v10, 2
     v14 = call fn0(v13)
     v15 = iadd v12, v14
     return v15
diff --git a/cranelift/filetests/filetests/isa/x86/abi64.clif b/cranelift/filetests/filetests/isa/x86/abi64.clif
index d99761a4d..9494e78c6 100644
--- a/cranelift/filetests/filetests/isa/x86/abi64.clif
+++ b/cranelift/filetests/filetests/isa/x86/abi64.clif
@@ -14,12 +14,6 @@ function %f() {
     sig2 = (f32, i64) -> f64 system_v
     ; check: sig2 = (f32 [%xmm0], i64 [%rdi]) -> f64 [%xmm0] system_v
 
-    sig3 = () -> i128 system_v
-    ; check: sig3 = () -> i64 [%rax], i64 [%rdx] system_v
-
-    sig4 = (i128) -> i128 system_v
-    ; check: sig4 = (i64 [%rdi], i64 [%rsi]) -> i64 [%rax], i64 [%rdx] system_v
-
 block0:
     return
 }
diff --git a/cranelift/filetests/filetests/isa/x86/bnot-b1.clif b/cranelift/filetests/filetests/isa/x86/bnot-b1.clif
deleted file mode 100644
index ef3736c54..000000000
--- a/cranelift/filetests/filetests/isa/x86/bnot-b1.clif
+++ /dev/null
@@ -1,14 +0,0 @@
-test binemit
-test run
-
-target x86_64
-
-function u0:323() -> b1 {
-block0:
-    [-,%rax] v221 = bconst.b1 false   ; bin: 40 b8 00000000
-    [-,%rcx] v222 = bconst.b1 true    ; bin: 40 b9 00000001
-    [-,%rax] v223 = bnot v221         ; bin: 40 f7 d0
-    [-,%rax] v224 = band v223, v222   ; bin: 40 21 c8
-    return v224
-}
-; run
diff --git a/cranelift/filetests/filetests/isa/x86/simd-bitselect-to-vselect-run.clif b/cranelift/filetests/filetests/isa/x86/simd-bitselect-to-vselect-run.clif
deleted file mode 100644
index 03cc64571..000000000
--- a/cranelift/filetests/filetests/isa/x86/simd-bitselect-to-vselect-run.clif
+++ /dev/null
@@ -1,39 +0,0 @@
-test run
-set opt_level=speed_and_size
-set enable_simd
-target x86_64 haswell
-
-;; Test if bitselect->vselect optimization works properly
-
-function %mask_from_icmp(i32x4, i32x4) -> i32x4 {
-block0(v0: i32x4, v1: i32x4):
-    v2 = icmp sge v0, v1
-    v3 = raw_bitcast.i32x4 v2
-    v4 = bitselect v3, v0, v1
-    return v4
-}
-; run: %mask_from_icmp([5 6 7 8], [1 10 20 7]) == [5 10 20 8]
-
-function %mask_casted(i64x2, i64x2, i32x4) -> i64x2 {
-block0(v0: i64x2, v1: i64x2, v2: i32x4):
-    v3 = raw_bitcast.i64x2 v2
-    v4 = bitselect v3, v0, v1
-    return v4
-}
-; run: %mask_casted([0 0], [0xFFFFFF 0xFFFF4F], [0xFFF1 0 0xF 0]) == [0xFF000E 0xFFFF40]
-
-function %good_const_mask(i32x4, i32x4) -> i32x4 {
-block0(v0: i32x4, v1: i32x4):
-    v2 = vconst.i32x4 [0x0000FF00 0x00FF00FF 0x00FF00FF 0xFF00FFFF]
-    v4 = bitselect v2, v0, v1
-    return v4
-}
-; run: %good_const_mask([0x1234 0x5678 0x1234 0x5678], [0xAAAA 0xAAAA 0xAAAA 0xAAAA]) == [0x12AA 0xAA78 0xAA34 0x5678]
-
-function %bad_const_mask(i32x4, i32x4) -> i32x4 {
-block0(v0: i32x4, v1: i32x4):
-    v2 = vconst.i32x4 [0x0000FF00 0x00FF00FF 0x00FF000F 0xFF00FFF0]
-    v4 = bitselect v2, v0, v1
-    return v4
-}
-; run: %bad_const_mask([0x1234 0x5678 0x1234 0x5678], [0xAAAA 0xAAAA 0xAAAA 0xAAAA]) == [0x12AA 0xAA78 0xAAA4 0x567A]
diff --git a/cranelift/filetests/filetests/isa/x86/simd-bitwise-legalize.clif b/cranelift/filetests/filetests/isa/x86/simd-bitwise-legalize.clif
index 7193aa2b5..102719351 100644
--- a/cranelift/filetests/filetests/isa/x86/simd-bitwise-legalize.clif
+++ b/cranelift/filetests/filetests/isa/x86/simd-bitwise-legalize.clif
@@ -91,10 +91,10 @@ block0:
     v2 = sshr v1, v0
     ; check:  v3 = x86_pextr v1, 0
     ; nextln: v4 = sshr v3, v0
-    ; nextln: v5 = x86_pinsr v1, v4, 0
+    ; nextln: v5 = x86_pinsr v1, 0, v4
     ; nextln: v6 = x86_pextr v1, 1
     ; nextln: v7 = sshr v6, v0
-    ; nextln: v2 = x86_pinsr v5, v7, 1
+    ; nextln: v2 = x86_pinsr v5, 1, v7
     return v2
 }
 
diff --git a/cranelift/filetests/filetests/isa/x86/simd-lane-access-binemit.clif b/cranelift/filetests/filetests/isa/x86/simd-lane-access-binemit.clif
index e5eea1f63..a1ffac182 100644
--- a/cranelift/filetests/filetests/isa/x86/simd-lane-access-binemit.clif
+++ b/cranelift/filetests/filetests/isa/x86/simd-lane-access-binemit.clif
@@ -10,7 +10,7 @@ block0:
 [-, %rax]   v0 = bconst.b8 true
 [-, %rbx]   v1 = bconst.b8 false
 [-, %xmm0]  v2 = splat.b8x16 v0
-[-, %xmm0]  v3 = x86_pinsr v2, v1, 10    ; bin: 66 0f 3a 20 c3 0a
+[-, %xmm0]  v3 = x86_pinsr v2, 10, v1    ; bin: 66 0f 3a 20 c3 0a
             return
 }
 
@@ -19,7 +19,7 @@ block0:
 [-, %rax]   v0 = iconst.i16 4
 [-, %rbx]   v1 = iconst.i16 5
 [-, %xmm1]  v2 = splat.i16x8 v0
-[-, %xmm1]  v3 = x86_pinsr v2, v1, 4    ; bin: 66 0f c4 cb 04
+[-, %xmm1]  v3 = x86_pinsr v2, 4, v1    ; bin: 66 0f c4 cb 04
             return
 }
 
@@ -28,7 +28,7 @@ block0:
 [-, %rax]   v0 = iconst.i32 42
 [-, %rbx]   v1 = iconst.i32 99
 [-, %xmm4]  v2 = splat.i32x4 v0
-[-, %xmm4]  v3 = x86_pinsr v2, v1, 2    ; bin: 66 0f 3a 22 e3 02
+[-, %xmm4]  v3 = x86_pinsr v2, 2, v1    ; bin: 66 0f 3a 22 e3 02
             return
 }
 
@@ -37,7 +37,7 @@ block0:
 [-, %rax]   v0 = bconst.b64 true
 [-, %rbx]   v1 = bconst.b64 false
 [-, %xmm2]  v2 = splat.b64x2 v0
-[-, %xmm2]  v3 = x86_pinsr v2, v1, 1    ; bin: 66 48 0f 3a 22 d3 01
+[-, %xmm2]  v3 = x86_pinsr v2, 1, v1    ; bin: 66 48 0f 3a 22 d3 01
             return
 }
 
diff --git a/cranelift/filetests/filetests/isa/x86/simd-lane-access-legalize.clif b/cranelift/filetests/filetests/isa/x86/simd-lane-access-legalize.clif
index 0f22ed366..548011640 100644
--- a/cranelift/filetests/filetests/isa/x86/simd-lane-access-legalize.clif
+++ b/cranelift/filetests/filetests/isa/x86/simd-lane-access-legalize.clif
@@ -55,7 +55,7 @@ block0:
 ; check:   block0:
 ; nextln:     v0 = iconst.i64 42
 ; nextln:     v2 = scalar_to_vector.i64x2 v0
-; nextln:     v1 = x86_pinsr v2, v0, 1
+; nextln:     v1 = x86_pinsr v2, 1, v0
 ; nextln:     return v1
 
 function %splat_b16() -> b16x8 {
@@ -67,7 +67,7 @@ block0:
 ; check:   block0:
 ; nextln:     v0 = bconst.b16 true
 ; nextln:     v2 = scalar_to_vector.b16x8 v0
-; nextln:     v3 = x86_pinsr v2, v0, 1
+; nextln:     v3 = x86_pinsr v2, 1, v0
 ; nextln:     v4 = raw_bitcast.i32x4 v3
 ; nextln:     v5 = x86_pshufd v4, 0
 ; nextln:     v1 = raw_bitcast.b16x8 v5
diff --git a/cranelift/filetests/filetests/isa/x86/simd-lane-access-run.clif b/cranelift/filetests/filetests/isa/x86/simd-lane-access-run.clif
index 00ebae26f..115a0be7c 100644
--- a/cranelift/filetests/filetests/isa/x86/simd-lane-access-run.clif
+++ b/cranelift/filetests/filetests/isa/x86/simd-lane-access-run.clif
@@ -62,7 +62,7 @@ block0:
     v1 = bconst.b8 true
     v2 = vconst.b8x16 [false false false false false false false false false false false false false
      false false false]
-    v3 = insertlane v2, v1, 10
+    v3 = insertlane v2, 10, v1
     v4 = extractlane v3, 10
     return v4
 }
@@ -72,7 +72,7 @@ function %insertlane_f32() -> b1 {
 block0:
     v0 = f32const 0x42.42
     v1 = vconst.f32x4 0x00
-    v2 = insertlane v1, v0, 1
+    v2 = insertlane v1, 1, v0
     v3 = extractlane v2, 1
     v4 = fcmp eq v3, v0
     return v4
@@ -83,7 +83,7 @@ function %insertlane_f64_lane1() -> b1 {
 block0:
     v0 = f64const 0x42.42
     v1 = vconst.f64x2 0x00
-    v2 = insertlane v1, v0, 1
+    v2 = insertlane v1, 1, v0
     v3 = extractlane v2, 1
     v4 = fcmp eq v3, v0
     return v4
@@ -94,7 +94,7 @@ function %insertlane_f64_lane0() -> b1 {
 block0:
     v0 = f64const 0x42.42
     v1 = vconst.f64x2 0x00
-    v2 = insertlane v1, v0, 0
+    v2 = insertlane v1, 0, v0
     v3 = extractlane v2, 0
     v4 = fcmp eq v3, v0
     return v4
@@ -135,7 +135,7 @@ block0:
     v1 = iconst.i32 99
 
     v2 = splat.i32x4 v0
-    v3 = insertlane v2, v1, 2
+    v3 = insertlane v2, 2, v1
 
     v4 = extractlane v3, 3
     v5 = icmp eq v4, v0
@@ -154,7 +154,7 @@ block0:
     v1 = f32const 0x99.99
 
     v2 = splat.f32x4 v0
-    v3 = insertlane v2, v1, 2
+    v3 = insertlane v2, 2, v1
 
     v4 = extractlane v3, 3
     v5 = fcmp eq v4, v0
diff --git a/cranelift/filetests/filetests/isa/x86/simd-vconst-rodata.clif b/cranelift/filetests/filetests/isa/x86/simd-vconst-rodata.clif
index 62acba80e..1cffdfe84 100644
--- a/cranelift/filetests/filetests/isa/x86/simd-vconst-rodata.clif
+++ b/cranelift/filetests/filetests/isa/x86/simd-vconst-rodata.clif
@@ -16,7 +16,7 @@ block0:
     return v0
 }
 
-; sameln: [FF, FF, 0, 0, FF, FF, 0, 0, FF, FF, 0, 0, FF, FF, FF, FF]
+; sameln: [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0]
 
 
 ; Since both jump tables and constants are emitted after the function body, it is important that they do not interfere.
diff --git a/cranelift/filetests/filetests/isa/x86/simd-vselect-binemit.clif b/cranelift/filetests/filetests/isa/x86/simd-vselect-binemit.clif
deleted file mode 100644
index a575c58f6..000000000
--- a/cranelift/filetests/filetests/isa/x86/simd-vselect-binemit.clif
+++ /dev/null
@@ -1,27 +0,0 @@
-test binemit
-set enable_simd
-target x86_64 haswell
-
-function %vselect_i8x16(b8x16, i8x16, i8x16) {
-block0(v0: b8x16 [%xmm0], v1: i8x16 [%xmm3], v2: i8x16 [%xmm5]):
-[-, %xmm5]  v3 = vselect v0, v1, v2  ; bin: 66 0f 38 10 eb
-            return
-}
-
-function %vselect_i16x8(b16x8, i16x8, i16x8) {
-block0(v0: b16x8 [%xmm0], v1: i16x8 [%xmm3], v2: i16x8 [%xmm5]):
-[-, %xmm5]  v3 = vselect v0, v1, v2  ; bin: 66 0f 38 10 eb
-            return
-}
-
-function %vselect_i32x4(b32x4, i32x4, i32x4) {
-block0(v0: b32x4 [%xmm0], v1: i32x4 [%xmm3], v2: i32x4 [%xmm5]):
-[-, %xmm5]  v3 = vselect v0, v1, v2  ; bin: 66 0f 38 14 eb
-            return
-}
-
-function %vselect_i64x2(b64x2, i64x2, i64x2) {
-block0(v0: b64x2 [%xmm0], v1: i64x2 [%xmm3], v2: i64x2 [%xmm5]):
-[-, %xmm5]  v3 = vselect v0, v1, v2  ; bin: 66 0f 38 15 eb
-            return
-}
diff --git a/cranelift/filetests/filetests/isa/x86/simd-vselect-legalize-to-bitselect.clif b/cranelift/filetests/filetests/isa/x86/simd-vselect-legalize-to-bitselect.clif
deleted file mode 100644
index 723539631..000000000
--- a/cranelift/filetests/filetests/isa/x86/simd-vselect-legalize-to-bitselect.clif
+++ /dev/null
@@ -1,45 +0,0 @@
-test legalizer
-set enable_simd
-target x86_64
-
-;; Test if vselect gets legalized if BLEND* instructions are not available
-
-function %vselect_i8x16(b8x16, i8x16, i8x16) -> i8x16 {
-block0(v0: b8x16, v1: i8x16, v2: i8x16):
-    v3 = vselect v0, v1, v2
-    ; check:  v4 = raw_bitcast.i8x16 v0
-    ; nextln: v5 = band v1, v4
-    ; nextln: v6 = band_not v2, v4
-    ; nextln: v3 = bor v5, v6
-    return v3
-}
-
-function %vselect_i16x8(b16x8, i16x8, i16x8) -> i16x8 {
-block0(v0: b16x8, v1: i16x8, v2: i16x8):
-    v3 = vselect v0, v1, v2
-    ; check:  v4 = raw_bitcast.i16x8 v0
-    ; nextln: v5 = band v1, v4
-    ; nextln: v6 = band_not v2, v4
-    ; nextln: v3 = bor v5, v6
-    return v3
-}
-
-function %vselect_i32x4(b32x4, i32x4, i32x4) -> i32x4 {
-block0(v0: b32x4, v1: i32x4, v2: i32x4):
-    v3 = vselect v0, v1, v2
-    ; check:  v4 = raw_bitcast.i32x4 v0
-    ; nextln: v5 = band v1, v4
-    ; nextln: v6 = band_not v2, v4
-    ; nextln: v3 = bor v5, v6
-    return v3
-}
-
-function %vselect_i64x2(b64x2, i64x2, i64x2) -> i64x2 {
-block0(v0: b64x2, v1: i64x2, v2: i64x2):
-    v3 = vselect v0, v1, v2
-    ; check:  v4 = raw_bitcast.i64x2 v0
-    ; nextln: v5 = band v1, v4
-    ; nextln: v6 = band_not v2, v4
-    ; nextln: v3 = bor v5, v6
-    return v3
-}
diff --git a/cranelift/filetests/filetests/isa/x86/simd-vselect-run.clif b/cranelift/filetests/filetests/isa/x86/simd-vselect-run.clif
deleted file mode 100644
index ac6feaa99..000000000
--- a/cranelift/filetests/filetests/isa/x86/simd-vselect-run.clif
+++ /dev/null
@@ -1,43 +0,0 @@
-test run
-set enable_simd
-target x86_64 haswell
-
-function %vselect_i8x16() -> i8x16 {
-block0:
-    v1 = vconst.b8x16 [false true false true false true true true true true false false false false false false]
-    v2 = vconst.i8x16 [100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115]
-    v3 = vconst.i8x16 [200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215]
-    v4 = vselect v1, v2, v3
-    return v4
-}
-; run: %vselect_i8x16() == [200 101 202 103 204 105 106 107 108 109 210 211 212 213 214 215]
-
-function %vselect_i16x8() -> i16x8 {
-block0:
-    v1 = vconst.b16x8 [false true false true false true true true]
-    v2 = vconst.i16x8 [100 101 102 103 104 105 106 107]
-    v3 = vconst.i16x8 [200 201 202 203 204 205 206 207]
-    v4 = vselect v1, v2, v3
-    return v4
-}
-; run: %vselect_i16x8() == [200 101 202 103 204 105 106 107]
-
-function %vselect_i32x4() -> i32x4 {
-block0:
-    v1 = vconst.b32x4 [false true false true]
-    v2 = vconst.i32x4 [100 101 102 103]
-    v3 = vconst.i32x4 [200 201 202 203]
-    v4 = vselect v1, v2, v3
-    return v4
-}
-; run: %vselect_i32x4() == [200 101 202 103]
-
-function %vselect_i64x2() -> i64x2 {
-block0:
-    v1 = vconst.b64x2 [false true]
-    v2 = vconst.i64x2 [100 101]
-    v3 = vconst.i64x2 [200 201]
-    v4 = vselect v1, v2, v3
-    return v4
-}
-; run: %vselect_i64x2() == [200 101]
diff --git a/cranelift/filetests/filetests/isa/x86/stack-addr32.clif b/cranelift/filetests/filetests/isa/x86/stack-addr32.clif
deleted file mode 100644
index 4b8a15379..000000000
--- a/cranelift/filetests/filetests/isa/x86/stack-addr32.clif
+++ /dev/null
@@ -1,33 +0,0 @@
-; binary emission of stack address instructions on i686.
-test binemit
-set opt_level=none
-target i686 haswell
-
-; The binary encodings can be verified with the command:
-;
-;   sed -ne 's/^ *; asm: *//p' filetests/isa/x86/stack-addr32.clif | llvm-mc -show-encoding -triple=i686
-;
-
-function %stack_addr() {
-           ss0 = incoming_arg 8, offset 0
-           ss1 = incoming_arg 1024, offset -1024
-           ss2 = incoming_arg 1024, offset -2048
-           ss3 = incoming_arg 8, offset -2056
-           ss4 = explicit_slot 8, offset 0
-           ss5 = explicit_slot 8, offset 1024
-
-block0:
-[-,%rcx]   v0 = stack_addr.i32 ss0                      ; bin: 8d 8c 24 00000808
-[-,%rcx]   v1 = stack_addr.i32 ss1                      ; bin: 8d 8c 24 00000408
-[-,%rcx]   v2 = stack_addr.i32 ss2                      ; bin: 8d 8c 24 00000008
-[-,%rcx]   v3 = stack_addr.i32 ss3                      ; bin: 8d 8c 24 00000000
-[-,%rcx]   v4 = stack_addr.i32 ss4                      ; bin: 8d 8c 24 00000808
-[-,%rcx]   v5 = stack_addr.i32 ss5                      ; bin: 8d 8c 24 00000c08
-
-[-,%rcx]   v20 = stack_addr.i32 ss4+1                   ; bin: 8d 8c 24 00000809
-[-,%rcx]   v21 = stack_addr.i32 ss4+2                   ; bin: 8d 8c 24 0000080a
-[-,%rcx]   v22 = stack_addr.i32 ss4+2048                ; bin: 8d 8c 24 00001008
-[-,%rcx]   v23 = stack_addr.i32 ss4-4096                ; bin: 8d 8c 24 fffff808
-
-           return
-}
diff --git a/cranelift/filetests/filetests/isa/x86/windows_fastcall_x64.clif b/cranelift/filetests/filetests/isa/x86/windows_fastcall_x64.clif
index cb1856ca3..8e8d35647 100644
--- a/cranelift/filetests/filetests/isa/x86/windows_fastcall_x64.clif
+++ b/cranelift/filetests/filetests/isa/x86/windows_fastcall_x64.clif
@@ -110,13 +110,6 @@ block0(v0: f32, v1: f64, v2: i64, v3: i64):
 ; nextln: return v1, v5
 ; nextln: }
 
-function %ret_val_i128(i64, i64) -> i128 windows_fastcall {
-block0(v0: i64, v1: i64):
-    v2 = iconcat v0, v1
-    return v2
-}
-; check: function %ret_val_i128(i64 [%rdx], i64 [%r8], i64 sret [%rcx], i64 fp [%rbp]) -> i64 sret [%rax], i64 fp [%rbp] windows_fastcall {
-
 function %internal_stack_arg_function_call(i64) -> i64 windows_fastcall {
   fn0 = %foo(i64, i64, i64, i64) -> i64 windows_fastcall
   fn1 = %foo2(i64, i64, i64, i64) -> i64 windows_fastcall
diff --git a/cranelift/filetests/filetests/legalizer/popcnt-i128.clif b/cranelift/filetests/filetests/legalizer/popcnt-i128.clif
index 6d07f3263..f4919f478 100644
--- a/cranelift/filetests/filetests/legalizer/popcnt-i128.clif
+++ b/cranelift/filetests/filetests/legalizer/popcnt-i128.clif
@@ -1,5 +1,5 @@
 test legalizer
-target x86_64 haswell
+target i686
 
 function %foo() -> i128 {
 block0:
@@ -10,12 +10,22 @@ block0:
     return v4
 }
 
-; check: v1 = iconst.i64 0x0064_0000_0042
-; check: v2 = iconst.i64 0x007f_1010_0042
+; check: v5 = iconst.i32 66
+; check: v6 = iconst.i32 100
+; check: v1 = iconcat v5, v6
+; check: v7 = iconst.i32 0x1010_0042
+; check: v8 = iconst.i32 127
+; check: v2 = iconcat v7, v8
 ; check: v3 = iconcat v1, v2
-; check: v5 = popcnt v1
-; check: v6 = popcnt v2
-; check: v7 = iadd v5, v6
-; check: v8 = iconst.i64 0
-; check: v4 = iconcat v7, v8
-; check: return v7, v8
+; check: v9 = popcnt v1
+; check: v10 = popcnt v2
+; check: v12, v13 = isplit v9
+; check: v14, v15 = isplit v10
+; check: v16, v17 = iadd_ifcout v12, v14
+; check: v18 = iadd_ifcin v13, v15, v17
+; check: v11 = iconcat v16, v18
+; check: v20 = iconst.i32 0
+; check: v21 = iconst.i32 0
+; check: v19 = iconcat v20, v21
+; check: v4 = iconcat v11, v19
+; check: return v16, v18, v20, v21
diff --git a/cranelift/filetests/filetests/parser/tiny.clif b/cranelift/filetests/filetests/parser/tiny.clif
index 42fa5a815..3f825e6ea 100644
--- a/cranelift/filetests/filetests/parser/tiny.clif
+++ b/cranelift/filetests/filetests/parser/tiny.clif
@@ -67,13 +67,13 @@ function %lanes() {
 block0:
     v0 = iconst.i32x4 2
     v1 = extractlane v0, 3
-    v2 = insertlane v0, v1, 1
+    v2 = insertlane v0, 1, v1
 }
 ; sameln: function %lanes() fast {
 ; nextln: block0:
 ; nextln:     v0 = iconst.i32x4 2
 ; nextln:     v1 = extractlane v0, 3
-; nextln:     v2 = insertlane v0, v1, 1
+; nextln:     v2 = insertlane v0, 1, v1
 ; nextln: }
 
 ; Integer condition codes.
diff --git a/cranelift/filetests/filetests/simple_preopt/bitselect.clif b/cranelift/filetests/filetests/simple_preopt/bitselect.clif
deleted file mode 100644
index 684d91ee3..000000000
--- a/cranelift/filetests/filetests/simple_preopt/bitselect.clif
+++ /dev/null
@@ -1,50 +0,0 @@
-test simple_preopt
-target x86_64
-
-;; Test replacement of bitselect with vselect for special masks
-
-function %mask_from_icmp(i8x16, i8x16) -> i8x16 {
-block0(v0: i8x16, v1: i8x16):
-    v2 = icmp eq v0, v1
-    v3 = raw_bitcast.i8x16 v2
-    v4 = bitselect v3, v0, v1
-    ; check: v4 = vselect v2, v0, v1
-    return v4
-}
-
-function %mask_casted(i8x16, i8x16, i32x4) -> i8x16 {
-block0(v0: i8x16, v1: i8x16, v2: i32x4):
-    v3 = raw_bitcast.i8x16 v2
-    v4 = bitselect v3, v0, v1
-    ; check: v4 = bitselect v3, v0, v1
-    return v4
-}
-
-function %good_const_mask_i8x16(i8x16, i8x16) -> i8x16 {
-block0(v0: i8x16, v1: i8x16):
-    v3 = vconst.i8x16 [0 0 0xFF 0 0 0xFF 0 0 0 0 0xFF 0 0 0 0 0xFF]
-    v4 = bitselect v3, v0, v1
-    ; check:  v5 = raw_bitcast.b8x16 v3
-    ; nextln: v4 = vselect v5, v0, v1
-    return v4
-}
-
-function %good_const_mask_i16x8(i16x8, i16x8) -> i16x8 {
-block0(v0: i16x8, v1: i16x8):
-    v3 = vconst.i16x8 [0x0000 0xFF00 0x0000 0x00FF 0x0000 0xFFFF 0x00FF 0xFFFF]
-    v4 = bitselect v3, v0, v1
-    ; check:  v5 = raw_bitcast.b8x16 v3
-    ; nextln: v6 = raw_bitcast.i8x16 v0
-    ; nextln: v7 = raw_bitcast.i8x16 v1
-    ; nextln: v8 = vselect v5, v6, v7
-    ; nextln: v4 = raw_bitcast.i16x8 v8
-    return v4
-}
-
-function %bad_const_mask(i8x16, i8x16) -> i8x16 {
-block0(v0: i8x16, v1: i8x16):
-    v3 = vconst.i8x16 [0 0 0xF0 0 0 0xFF 0 0 0 0 0xFF 0 0 0 0 0xFF]
-    v4 = bitselect v3, v0, v1
-    ; check: v4 = bitselect v3, v0, v1
-    return v4
-}
diff --git a/cranelift/filetests/filetests/verifier/simd-lane-index.clif b/cranelift/filetests/filetests/verifier/simd-lane-index.clif
index b8051a6b5..2f7ca8d09 100644
--- a/cranelift/filetests/filetests/verifier/simd-lane-index.clif
+++ b/cranelift/filetests/filetests/verifier/simd-lane-index.clif
@@ -6,7 +6,7 @@ function %insertlane_i32x4() {
 block0:
     v0 = vconst.i32x4 [0 0 0 0]
     v1 = iconst.i32 42
-    v2 = insertlane v0, v1, 4 ; error: The lane 4 does not index into the type i32x4
+    v2 = insertlane v0, 4, v1 ; error: The lane 4 does not index into the type i32x4
     return
 }
 
@@ -14,7 +14,7 @@ function %insertlane_b16x8() {
 block0:
     v0 = vconst.b16x8 [false false false false false false false false]
     v1 = bconst.b16 true
-    v2 = insertlane v0, v1, 8 ; error: The lane 8 does not index into the type b16x8
+    v2 = insertlane v0, 8, v1 ; error: The lane 8 does not index into the type b16x8
     return
 }
 
@@ -22,7 +22,7 @@ function %insertlane_f64x2() {
 block0:
     v0 = vconst.f64x2 0x00
     v1 = f64const 0x0.1
-    v2 = insertlane v0, v1, 2 ; error: The lane 2 does not index into the type f64x2
+    v2 = insertlane v0, 2, v1 ; error: The lane 2 does not index into the type f64x2
     return
 }
 
diff --git a/cranelift/filetests/filetests/wasm/multi-val-call-legalize-args.clif b/cranelift/filetests/filetests/wasm/multi-val-call-legalize-args.clif
deleted file mode 100644
index b57090d85..000000000
--- a/cranelift/filetests/filetests/wasm/multi-val-call-legalize-args.clif
+++ /dev/null
@@ -1,24 +0,0 @@
-test legalizer
-target x86_64 haswell
-
-;; Test if arguments are legalized if function uses sret
-
-function %call_indirect_with_split_arg(i64, i64, i64) {
-    ; check: ss0 = sret_slot 32
-    sig0 = (i128) -> i64, i64, i64, i64
-    ; check: sig0 = (i64 [%rsi], i64 [%rdx], i64 sret [%rdi]) -> i64 sret [%rax] fast
-block0(v0: i64, v1: i64, v2: i64):
-    v3 = iconcat v1, v2
-    v4, v5, v6, v7 = call_indirect sig0, v0(v3)
-    ; check: v8 = stack_addr.i64 ss0
-    ; check: v9 = call_indirect sig0, v0(v1, v2, v8)
-    ; check: v10 = load.i64 notrap aligned v9
-    ; check: v4 -> v10
-    ; check: v11 = load.i64 notrap aligned v9+8
-    ; check: v5 -> v11
-    ; check: v12 = load.i64 notrap aligned v9+16
-    ; check: v6 -> v12
-    ; check: v13 = load.i64 notrap aligned v9+24
-    ; check: v7 -> v13
-    return
-}
diff --git a/cranelift/filetests/src/test_run.rs b/cranelift/filetests/src/test_run.rs
index 58888bf0f..0044779ba 100644
--- a/cranelift/filetests/src/test_run.rs
+++ b/cranelift/filetests/src/test_run.rs
@@ -58,7 +58,7 @@ impl SubTest for TestRun {
                 // running x86_64 code on aarch64 platforms.
                 let compiled_fn = compiler
                     .compile(func.clone().into_owned())
-                    .map_err(|e| format!("{:?}", e))?;
+                    .map_err(|e| e.to_string())?;
                 command.run(|_, args| Ok(compiled_fn.call(args)))?;
             }
         }
diff --git a/crates/test-programs/tests/wasm_tests/runtime.rs b/crates/test-programs/tests/wasm_tests/runtime.rs
index de465d130..0157a9c61 100644
--- a/crates/test-programs/tests/wasm_tests/runtime.rs
+++ b/crates/test-programs/tests/wasm_tests/runtime.rs
@@ -1,8 +1,8 @@
-use anyhow::Context;
+use anyhow::{bail, Context};
 use std::fs::File;
 use std::path::Path;
 use wasi_common::VirtualDirEntry;
-use wasmtime::{Linker, Module, Store};
+use wasmtime::{Instance, Module, Store};
 
 #[derive(Clone, Copy, Debug)]
 pub enum PreopenType {
@@ -48,19 +48,36 @@ pub fn instantiate(
     let (reader, _writer) = os_pipe::pipe()?;
     builder.stdin(reader_to_file(reader));
     let snapshot1 = wasmtime_wasi::Wasi::new(&store, builder.build()?);
+    let module = Module::new(&store, &data).context("failed to create wasm module")?;
+    let imports = module
+        .imports()
+        .map(|i| {
+            let field_name = i.name();
+            if let Some(export) = snapshot1.get_export(field_name) {
+                Ok(export.clone().into())
+            } else {
+                bail!(
+                    "import {} was not found in module {}",
+                    field_name,
+                    i.module()
+                )
+            }
+        })
+        .collect::<Result<Vec<_>, _>>()?;
 
-    let mut linker = Linker::new(&store);
-
-    snapshot1.add_to_linker(&mut linker)?;
+    let instance = Instance::new(&module, &imports).context(format!(
+        "error while instantiating Wasm module '{}'",
+        bin_name,
+    ))?;
 
-    let module = Module::new(&store, &data).context("failed to create wasm module")?;
+    instance
+        .get_export("_start")
+        .context("expected a _start export")?
+        .into_func()
+        .context("expected export to be a func")?
+        .call(&[])?;
 
-    linker
-        .module("", &module)
-        .and_then(|m| m.get_default(""))
-        .and_then(|f| f.get0::<()>())
-        .and_then(|f| f().map_err(Into::into))
-        .context(format!("error while testing Wasm module '{}'", bin_name,))
+    Ok(())
 }
 
 #[cfg(unix)]
diff --git a/crates/wiggle/tests/keywords.rs b/crates/wiggle/tests/keywords.rs
new file mode 100644
index 000000000..ea002fcc6
--- /dev/null
+++ b/crates/wiggle/tests/keywords.rs
@@ -0,0 +1,64 @@
+//! Tests to check that keywords in `witx` files are escaped.
+//!
+//! No `#[test]` functions are defined below because the `wiggle::from_witx!` macro expanding into
+//! syntactically correct Rust code at compile time is the subject under test.
+
+/// Test that an enum variant that conflicts with a Rust keyword can be compiled properly.
+mod enum_test {
+    wiggle::from_witx!({
+        witx_literal:
+            "(typename $self
+                 (enum u8
+                     $self
+                     $2big
+                 )
+             )",
+        ctx: DummyCtx,
+    });
+}
+
+/// Test module, trait, function, and function parameter names conflicting with Rust keywords.
+///
+/// We use `self` because the camel-cased trait name `Self` is *also* a strict keyword. This lets
+/// us simultaneously test the name of the module and the generated trait.
+mod module_trait_fn_and_arg_test {
+    use wiggle_test::WasiCtx;
+    wiggle::from_witx!({
+        witx_literal:
+            "(module $self
+                 (@interface func (export \"fn\")
+                     (param $use u32)
+                     (param $virtual u32)
+                 )
+             )",
+        ctx: WasiCtx,
+    });
+    impl<'a> self_::Self_ for WasiCtx<'a> {
+        #[allow(unused_variables)]
+        fn fn_(&self, use_: u32, virtual_: u32) -> Result<(), ()> {
+            unimplemented!();
+        }
+    }
+}
+
+/// Test that a struct and member names conflicting with Rust keywords can be compiled properly.
+mod struct_test {
+    wiggle::from_witx!({
+        witx_literal:
+            "(typename $self
+                 (struct
+                     (field $become s32)
+                     (field $mut s32)
+                 )
+             )",
+        ctx: DummyCtx,
+    });
+}
+
+/// Test that a union variant that conflicts with a Rust keyword can be compiled properly.
+mod union_test {
+    wiggle::from_witx!({
+        witx: ["tests/keywords_union.witx"],
+        ctx: DummyCtx,
+    });
+}
diff --git a/crates/wiggle/tests/keywords_union.witx b/crates/wiggle/tests/keywords_union.witx
new file mode 100644
index 000000000..14d29b70d
--- /dev/null
+++ b/crates/wiggle/tests/keywords_union.witx
@@ -0,0 +1,15 @@
+(typename $union
+  (enum u8
+    $self
+    $power
+  )
+)
+
+(typename $self
+  (union $union
+    ;; A union variant that will expand to a strict keyword `Self`.
+    (field $self (@witx pointer f32))
+    ;; Oh it's true, that there's power in a union!
+    (field $power (@witx pointer f32))
+  )
+)
diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs
index 41a0e155a..c8edbd1fb 100644
--- a/tests/all/cli_tests.rs
+++ b/tests/all/cli_tests.rs
@@ -256,97 +256,3 @@ fn exit126_wasi_snapshot1() -> Result<()> {
     assert!(String::from_utf8_lossy(&output.stderr).contains("invalid exit status"));
     Ok(())
 }
-
-// Run a minimal command program.
-#[test]
-fn minimal_command() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/minimal-command.wat")?;
-    let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    assert_eq!(stdout, "");
-    Ok(())
-}
-
-// Run a minimal reactor program.
-#[test]
-fn minimal_reactor() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/minimal-reactor.wat")?;
-    let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    assert_eq!(stdout, "");
-    Ok(())
-}
-
-// Attempt to call invoke on a command.
-#[test]
-fn command_invoke() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/minimal-command.wat")?;
-    run_wasmtime(&[
-        "run",
-        wasm.path().to_str().unwrap(),
-        "--invoke",
-        "_start",
-        "--disable-cache",
-    ])?;
-    Ok(())
-}
-
-// Attempt to call invoke on a command.
-#[test]
-fn reactor_invoke() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/minimal-reactor.wat")?;
-    run_wasmtime(&[
-        "run",
-        wasm.path().to_str().unwrap(),
-        "--invoke",
-        "_initialize",
-        "--disable-cache",
-    ])?;
-    Ok(())
-}
-
-// Run the greeter test, which runs a preloaded reactor and a command.
-#[test]
-fn greeter() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/greeter_command.wat")?;
-    let stdout = run_wasmtime(&[
-        "run",
-        wasm.path().to_str().unwrap(),
-        "--disable-cache",
-        "--preload",
-        "reactor=tests/wasm/greeter_reactor.wat",
-    ])?;
-    assert_eq!(
-        stdout,
-        "Hello _initialize\nHello _start\nHello greet\nHello done\n"
-    );
-    Ok(())
-}
-
-// Run the greeter test, but this time preload a command.
-#[test]
-fn greeter_preload_command() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/greeter_reactor.wat")?;
-    let stdout = run_wasmtime(&[
-        "run",
-        wasm.path().to_str().unwrap(),
-        "--disable-cache",
-        "--preload",
-        "reactor=tests/wasm/hello_wasi_snapshot1.wat",
-    ])?;
-    assert_eq!(stdout, "Hello _initialize\n");
-    Ok(())
-}
-
-// Run the greeter test, which runs a preloaded reactor and a command.
-#[test]
-fn greeter_preload_callable_command() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/greeter_command.wat")?;
-    let stdout = run_wasmtime(&[
-        "run",
-        wasm.path().to_str().unwrap(),
-        "--disable-cache",
-        "--preload",
-        "reactor=tests/wasm/greeter_callable_command.wat",
-    ])?;
-    assert_eq!(stdout, "Hello _start\nHello callable greet\nHello done\n");
-    Ok(())
-}
diff --git a/tests/all/custom_signal_handler.rs b/tests/all/custom_signal_handler.rs
index 50425f0df..990c2af37 100644
--- a/tests/all/custom_signal_handler.rs
+++ b/tests/all/custom_signal_handler.rs
@@ -113,10 +113,10 @@ mod tests {
                 .unwrap_err()
                 .downcast::<Trap>()?;
             assert!(
-                trap.to_string()
-                    .contains("wasm trap: out of bounds memory access"),
+                trap.message()
+                    .starts_with("wasm trap: out of bounds memory access"),
                 "bad trap message: {:?}",
-                trap.to_string()
+                trap.message()
             );
         }
 
@@ -140,8 +140,8 @@ mod tests {
                 .unwrap_err()
                 .downcast::<Trap>()?;
             assert!(trap
-                .to_string()
-                .contains("wasm trap: out of bounds memory access"));
+                .message()
+                .starts_with("wasm trap: out of bounds memory access"));
         }
         Ok(())
     }
diff --git a/tests/all/func.rs b/tests/all/func.rs
index 4d8f5d870..16da165ba 100644
--- a/tests/all/func.rs
+++ b/tests/all/func.rs
@@ -181,7 +181,7 @@ fn trap_smoke() -> Result<()> {
     let store = Store::default();
     let f = Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("test")) });
     let err = f.call(&[]).unwrap_err().downcast::<Trap>()?;
-    assert!(err.to_string().contains("test"));
+    assert_eq!(err.message(), "test");
     assert!(err.i32_exit_status().is_none());
     Ok(())
 }
@@ -203,7 +203,7 @@ fn trap_import() -> Result<()> {
     .err()
     .unwrap()
     .downcast::<Trap>()?;
-    assert!(trap.to_string().contains("foo"));
+    assert_eq!(trap.message(), "foo");
     Ok(())
 }
 
@@ -397,8 +397,9 @@ fn func_write_nothing() -> anyhow::Result<()> {
     let ty = FuncType::new(Box::new([]), Box::new([ValType::I32]));
     let f = Func::new(&store, ty, |_, _, _| Ok(()));
     let err = f.call(&[]).unwrap_err().downcast::<Trap>()?;
-    assert!(err
-        .to_string()
-        .contains("function attempted to return an incompatible value"));
+    assert_eq!(
+        err.message(),
+        "function attempted to return an incompatible value"
+    );
     Ok(())
 }
diff --git a/tests/all/import_calling_export.rs b/tests/all/import_calling_export.rs
index 9e7f96b07..7affdd875 100644
--- a/tests/all/import_calling_export.rs
+++ b/tests/all/import_calling_export.rs
@@ -90,8 +90,9 @@ fn test_returns_incorrect_type() -> Result<()> {
         .call(&[])
         .expect_err("the execution should fail")
         .downcast::<Trap>()?;
-    assert!(trap
-        .to_string()
-        .contains("function attempted to return an incompatible value"));
+    assert_eq!(
+        trap.message(),
+        "function attempted to return an incompatible value"
+    );
     Ok(())
 }
diff --git a/tests/all/linker.rs b/tests/all/linker.rs
index b2c7a64da..b84d7e9c1 100644
--- a/tests/all/linker.rs
+++ b/tests/all/linker.rs
@@ -66,40 +66,7 @@ fn link_twice_bad() -> Result<()> {
 }
 
 #[test]
-fn function_interposition() -> Result<()> {
-    let store = Store::default();
-    let mut linker = Linker::new(&store);
-    linker.allow_shadowing(true);
-    let mut module = Module::new(
-        &store,
-        r#"(module (func (export "green") (result i32) (i32.const 7)))"#,
-    )?;
-    for _ in 0..4 {
-        let instance = linker.instantiate(&module)?;
-        linker.define(
-            "red",
-            "green",
-            instance.get_export("green").unwrap().clone(),
-        )?;
-        module = Module::new(
-            &store,
-            r#"(module
-                (import "red" "green" (func (result i32)))
-                (func (export "green") (result i32) (i32.mul (call 0) (i32.const 2)))
-            )"#,
-        )?;
-    }
-    let instance = linker.instantiate(&module)?;
-    let func = instance.get_export("green").unwrap().into_func().unwrap();
-    let func = func.get0::<i32>()?;
-    assert_eq!(func()?, 112);
-    Ok(())
-}
-
-// Same as `function_interposition`, but the linker's name for the function
-// differs from the module's name.
-#[test]
-fn function_interposition_renamed() -> Result<()> {
+fn interposition() -> Result<()> {
     let store = Store::default();
     let mut linker = Linker::new(&store);
     linker.allow_shadowing(true);
@@ -128,32 +95,3 @@ fn function_interposition_renamed() -> Result<()> {
     assert_eq!(func()?, 112);
     Ok(())
 }
-
-// Similar to `function_interposition`, but use `Linker::instance` instead of
-// `Linker::define`.
-#[test]
-fn module_interposition() -> Result<()> {
-    let store = Store::default();
-    let mut linker = Linker::new(&store);
-    linker.allow_shadowing(true);
-    let mut module = Module::new(
-        &store,
-        r#"(module (func (export "export") (result i32) (i32.const 7)))"#,
-    )?;
-    for _ in 0..4 {
-        let instance = linker.instantiate(&module)?;
-        linker.instance("instance", &instance)?;
-        module = Module::new(
-            &store,
-            r#"(module
-                (import "instance" "export" (func (result i32)))
-                (func (export "export") (result i32) (i32.mul (call 0) (i32.const 2)))
-            )"#,
-        )?;
-    }
-    let instance = linker.instantiate(&module)?;
-    let func = instance.get_export("export").unwrap().into_func().unwrap();
-    let func = func.get0::<i32>()?;
-    assert_eq!(func()?, 112);
-    Ok(())
-}
diff --git a/tests/all/traps.rs b/tests/all/traps.rs
index 575e6741b..f4ae458f4 100644
--- a/tests/all/traps.rs
+++ b/tests/all/traps.rs
@@ -25,7 +25,7 @@ fn test_trap_return() -> Result<()> {
         .expect("error calling function")
         .downcast::<Trap>()?;
 
-    assert!(e.to_string().contains("test 123"));
+    assert_eq!(e.message(), "test 123");
 
     Ok(())
 }
@@ -64,9 +64,9 @@ fn test_trap_trace() -> Result<()> {
     assert_eq!(trace[1].func_offset(), 1);
     assert_eq!(trace[1].module_offset(), 0x21);
     assert!(
-        e.to_string().contains("unreachable"),
+        e.message().contains("unreachable"),
         "wrong message: {}",
-        e.to_string()
+        e.message()
     );
 
     Ok(())
@@ -103,7 +103,7 @@ fn test_trap_trace_cb() -> Result<()> {
     assert_eq!(trace[0].func_index(), 2);
     assert_eq!(trace[1].module_name().unwrap(), "hello_mod");
     assert_eq!(trace[1].func_index(), 1);
-    assert!(e.to_string().contains("cb throw"));
+    assert_eq!(e.message(), "cb throw");
 
     Ok(())
 }
@@ -135,7 +135,7 @@ fn test_trap_stack_overflow() -> Result<()> {
         assert_eq!(trace[i].func_index(), 0);
         assert_eq!(trace[i].func_name(), Some("run"));
     }
-    assert!(e.to_string().contains("call stack exhausted"));
+    assert!(e.message().contains("call stack exhausted"));
 
     Ok(())
 }
@@ -234,11 +234,7 @@ fn trap_start_function_import() -> Result<()> {
     let sig = FuncType::new(Box::new([]), Box::new([]));
     let func = Func::new(&store, sig, |_, _, _| Err(Trap::new("user trap")));
     let err = Instance::new(&module, &[func.into()]).err().unwrap();
-    assert!(err
-        .downcast_ref::<Trap>()
-        .unwrap()
-        .to_string()
-        .contains("user trap"));
+    assert_eq!(err.downcast_ref::<Trap>().unwrap().message(), "user trap");
     Ok(())
 }
 
@@ -377,9 +373,7 @@ fn call_signature_mismatch() -> Result<()> {
         .unwrap()
         .downcast::<Trap>()
         .unwrap();
-    assert!(err
-        .to_string()
-        .contains("wasm trap: indirect call type mismatch"));
+    assert_eq!(err.message(), "wasm trap: indirect call type mismatch");
     Ok(())
 }
 
diff --git a/tests/wasm/greeter_callable_command.wat b/tests/wasm/greeter_callable_command.wat
deleted file mode 100644
index 939debaf4..000000000
--- a/tests/wasm/greeter_callable_command.wat
+++ /dev/null
@@ -1,23 +0,0 @@
-;; Like greeter_reactor, but exports "_start" instead of "_initialize".
-(module
-  (import "wasi_snapshot_preview1" "fd_write"
-    (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
-  (func (export "_start")
-    (call $print (i32.const 32) (i32.const 22))
-  )
-  (func (export "greet")
-    (call $print (i32.const 64) (i32.const 21))
-  )
-  (func $print (param $ptr i32) (param $len i32)
-    (i32.store (i32.const 8) (local.get $len))
-    (i32.store (i32.const 4) (local.get $ptr))
-        (drop (call $__wasi_fd_write
-          (i32.const 1)
-          (i32.const 4)
-          (i32.const 1)
-          (i32.const 0)))
-  )
-  (memory (export "memory") 1)
-  (data (i32.const 32) "Hello callable _start\0a")
-  (data (i32.const 64) "Hello callable greet\0a")
-)
diff --git a/tests/wasm/greeter_command.wat b/tests/wasm/greeter_command.wat
deleted file mode 100644
index b80d197c5..000000000
--- a/tests/wasm/greeter_command.wat
+++ /dev/null
@@ -1,22 +0,0 @@
-(module
-  (import "wasi_snapshot_preview1" "fd_write"
-    (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
-  (import "reactor" "greet" (func $greet))
-  (func (export "_start")
-    (call $print (i32.const 32) (i32.const 13))
-    (call $greet)
-    (call $print (i32.const 64) (i32.const 11))
-  )
-  (func $print (param $ptr i32) (param $len i32)
-    (i32.store (i32.const 8) (local.get $len))
-    (i32.store (i32.const 4) (local.get $ptr))
-        (drop (call $__wasi_fd_write
-          (i32.const 1)
-          (i32.const 4)
-          (i32.const 1)
-          (i32.const 0)))
-  )
-  (memory (export "memory") 1)
-  (data (i32.const 32) "Hello _start\0a")
-  (data (i32.const 64) "Hello done\0a")
-)
diff --git a/tests/wasm/greeter_reactor.wat b/tests/wasm/greeter_reactor.wat
deleted file mode 100644
index 2f0914f8b..000000000
--- a/tests/wasm/greeter_reactor.wat
+++ /dev/null
@@ -1,22 +0,0 @@
-(module
-  (import "wasi_snapshot_preview1" "fd_write"
-    (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
-  (func (export "_initialize")
-    (call $print (i32.const 32) (i32.const 18))
-  )
-  (func (export "greet")
-    (call $print (i32.const 64) (i32.const 12))
-  )
-  (func $print (param $ptr i32) (param $len i32)
-    (i32.store (i32.const 8) (local.get $len))
-    (i32.store (i32.const 4) (local.get $ptr))
-        (drop (call $__wasi_fd_write
-          (i32.const 1)
-          (i32.const 4)
-          (i32.const 1)
-          (i32.const 0)))
-  )
-  (memory (export "memory") 1)
-  (data (i32.const 32) "Hello _initialize\0a")
-  (data (i32.const 64) "Hello greet\0a")
-)
diff --git a/tests/wasm/minimal-command.wat b/tests/wasm/minimal-command.wat
deleted file mode 100644
index 6e9f4f5ff..000000000
--- a/tests/wasm/minimal-command.wat
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-    (func (export "_start"))
-)
diff --git a/tests/wasm/minimal-reactor.wat b/tests/wasm/minimal-reactor.wat
deleted file mode 100644
index bf7bd2148..000000000
--- a/tests/wasm/minimal-reactor.wat
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-    (func (export "_initialize"))
-)