Commit f7cbd92e6c

Andrew Kelley <andrew@ziglang.org>
2021-12-05 05:55:50
Revert "Merge pull request #10270 from Luukdegram/behaviour-tests"
This reverts commit 725267f7c20f0ba588b472048a8c1fe1a328c714, reversing changes made to 2dae860de3494f97c9477af9282fe0131ff5c4cb. This test is failing: ```zig pub fn main() u8 { var e = foo(); const i = e catch 69; return i; } fn foo() anyerror!u8 { return 5; } ``` It's returning 69 instead of the expected value 5.
1 parent 117c046
Changed files (7)
ci/zinc/linux_test.sh
@@ -6,7 +6,6 @@ ZIG=$DEBUG_STAGING/bin/zig
 
 $ZIG test test/behavior.zig -fno-stage1 -fLLVM -I test
 $ZIG test test/behavior.zig -fno-stage1 -ofmt=c -I test
-$ZIG test test/behavior.zig -fno-stage1 -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin
 
 $ZIG build test-behavior         -fqemu -fwasmtime
 $ZIG build test-compiler-rt      -fqemu -fwasmtime
src/arch/wasm/CodeGen.zig
@@ -6,7 +6,6 @@ const testing = std.testing;
 const leb = std.leb;
 const mem = std.mem;
 const wasm = std.wasm;
-const log = std.log.scoped(.codegen);
 
 const Module = @import("../../Module.zig");
 const Decl = Module.Decl;
@@ -551,7 +550,7 @@ mir_extra: std.ArrayListUnmanaged(u32) = .{},
 initial_stack_value: WValue = .none,
 /// Arguments of this function declaration
 /// This will be set after `resolveCallingConventionValues`
-args: []WValue = &.{},
+args: []WValue = undefined,
 /// This will only be `.none` if the function returns void, or returns an immediate.
 /// When it returns a pointer to the stack, the `.local` tag will be active and must be populated
 /// before this function returns its execution to the caller.
@@ -563,6 +562,8 @@ const InnerError = error{
     CodegenFail,
     /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
     AnalysisFail,
+    /// Failed to emit MIR instructions to binary/textual representation.
+    EmitFail,
     /// Compiler implementation could not handle a large integer.
     Overflow,
 };
@@ -799,7 +800,7 @@ pub fn genFunc(self: *Self) InnerError!Result {
     emit.emitMir() catch |err| switch (err) {
         error.EmitFail => {
             self.err_msg = emit.error_msg.?;
-            return error.CodegenFail;
+            return error.EmitFail;
         },
         else => |e| return e,
     };
@@ -808,34 +809,8 @@ pub fn genFunc(self: *Self) InnerError!Result {
     return Result.appended;
 }
 
-pub fn genDecl(self: *Self) InnerError!Result {
-    const decl = self.decl;
-    assert(decl.has_tv);
-
-    log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
-
-    if (decl.val.castTag(.function)) |func_payload| {
-        _ = func_payload;
-        return self.fail("TODO wasm backend genDecl function pointer", .{});
-    } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
-        const ext_decl = extern_fn.data;
-        var func_type = try self.genFunctype(ext_decl.ty);
-        func_type.deinit(self.gpa);
-        ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
-        return Result.appended;
-    } else {
-        const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
-            break :init_val payload.data.init;
-        } else decl.val;
-        if (init_val.tag() != .unreachable_value) {
-            return try self.genTypedValue(decl.ty, init_val);
-        }
-        return Result.appended;
-    }
-}
-
 /// Generates the wasm bytecode for the declaration belonging to `Context`
-fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
+pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
     if (val.isUndef()) {
         try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target)));
         return Result.appended;
@@ -847,16 +822,16 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
                 .function => val.castTag(.function).?.data.owner_decl,
                 else => unreachable,
             };
-            return try self.lowerDeclRef(ty, val, fn_decl);
+            return try self.lowerDeclRef(fn_decl);
         },
         .Optional => {
             var opt_buf: Type.Payload.ElemType = undefined;
             const payload_type = ty.optionalChild(&opt_buf);
             if (ty.isPtrLikeOptional()) {
                 if (val.castTag(.opt_payload)) |payload| {
-                    return try self.genTypedValue(payload_type, payload.data);
+                    return try self.genDecl(payload_type, payload.data);
                 } else if (!val.isNull()) {
-                    return try self.genTypedValue(payload_type, val);
+                    return try self.genDecl(payload_type, val);
                 } else {
                     try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target)));
                     return Result.appended;
@@ -864,7 +839,7 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
             }
             // `null-tag` byte
             try self.code.appendNTimes(@boolToInt(!val.isNull()), 4);
-            const pl_result = try self.genTypedValue(
+            const pl_result = try self.genDecl(
                 payload_type,
                 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
             );
@@ -880,7 +855,7 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
                 if (ty.sentinel()) |sentinel| {
                     try self.code.appendSlice(payload.data);
 
-                    switch (try self.genTypedValue(ty.childType(), sentinel)) {
+                    switch (try self.genDecl(ty.childType(), sentinel)) {
                         .appended => return Result.appended,
                         .externally_managed => |data| {
                             try self.code.appendSlice(data);
@@ -894,20 +869,22 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
                 const elem_vals = val.castTag(.array).?.data;
                 const elem_ty = ty.elemType();
                 for (elem_vals) |elem_val| {
-                    switch (try self.genTypedValue(elem_ty, elem_val)) {
+                    switch (try self.genDecl(elem_ty, elem_val)) {
                         .appended => {},
-                        .externally_managed => |data| try self.code.appendSlice(data),
+                        .externally_managed => |data| {
+                            try self.code.appendSlice(data);
+                        },
                     }
                 }
                 return Result.appended;
             },
-            else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}),
+            else => return self.fail("TODO implement genDecl for array type value: {s}", .{@tagName(val.tag())}),
         },
         .Int => {
             const info = ty.intInfo(self.target);
             const abi_size = @intCast(usize, ty.abiSize(self.target));
             // todo: Implement integer sizes larger than 64bits
-            if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits});
+            if (info.bits > 64) return self.fail("TODO: Implement genDecl for integer bit size: {d}", .{info.bits});
             var buf: [8]u8 = undefined;
             if (info.signedness == .unsigned) {
                 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
@@ -929,7 +906,8 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
             for (field_vals) |field_val, index| {
                 const field_ty = ty.structFieldType(index);
                 if (!field_ty.hasCodeGenBits()) continue;
-                switch (try self.genTypedValue(field_ty, field_val)) {
+
+                switch (try self.genDecl(field_ty, field_val)) {
                     .appended => {},
                     .externally_managed => |payload| try self.code.appendSlice(payload),
                 }
@@ -945,21 +923,21 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
         .Pointer => switch (val.tag()) {
             .variable => {
                 const decl = val.castTag(.variable).?.data.owner_decl;
-                return try self.lowerDeclRef(ty, val, decl);
+                return try self.lowerDeclRef(decl);
             },
             .decl_ref => {
                 const decl = val.castTag(.decl_ref).?.data;
-                return try self.lowerDeclRef(ty, val, decl);
+                return try self.lowerDeclRef(decl);
             },
             .slice => {
                 const slice = val.castTag(.slice).?.data;
                 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
                 const ptr_ty = ty.slicePtrFieldType(&buf);
-                switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
+                switch (try self.genDecl(ptr_ty, slice.ptr)) {
                     .externally_managed => |data| try self.code.appendSlice(data),
                     .appended => {},
                 }
-                switch (try self.genTypedValue(Type.usize, slice.len)) {
+                switch (try self.genDecl(Type.usize, slice.len)) {
                     .externally_managed => |data| try self.code.appendSlice(data),
                     .appended => {},
                 }
@@ -971,25 +949,13 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
     }
 }
 
-fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result {
-    if (ty.isSlice()) {
-        var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-        const slice_ty = ty.slicePtrFieldType(&buf);
-        switch (try self.genTypedValue(slice_ty, val)) {
-            .appended => {},
-            .externally_managed => |payload| try self.code.appendSlice(payload),
-        }
-        var slice_len: Value.Payload.U64 = .{
-            .base = .{ .tag = .int_u64 },
-            .data = val.sliceLen(),
-        };
-        return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
-    }
+fn lowerDeclRef(self: *Self, decl: *Module.Decl) InnerError!Result {
+    decl.alive = true;
 
     const offset = @intCast(u32, self.code.items.len);
     const atom = &self.decl.link.wasm;
     const target_sym_index = decl.link.wasm.sym_index;
-    decl.alive = true;
+
     if (decl.ty.zigTypeTag() == .Fn) {
         // We found a function pointer, so add it to our table,
         // as function pointers are not allowed to be stored inside the data section,
@@ -1048,7 +1014,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
 
             const ret_ty = fn_ty.fnReturnType();
             switch (ret_ty.zigTypeTag()) {
-                .ErrorUnion, .Optional, .Pointer => result.return_value = try self.allocLocal(Type.initTag(.i32)),
+                .ErrorUnion, .Optional => result.return_value = try self.allocLocal(Type.initTag(.i32)),
                 .Int, .Float, .Bool, .Void, .NoReturn => {},
                 else => return self.fail("TODO: Implement function return type {}", .{ret_ty}),
             }
@@ -1062,11 +1028,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
                 };
 
                 try self.moveStack(offset, result.return_value.local);
-
-                // We want to make sure the return value's stack value doesn't get overwritten,
-                // so set initial stack value to current's position instead.
-                try self.addLabel(.global_get, 0);
-                try self.addLabel(.local_set, self.initial_stack_value.local);
             }
         },
         else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}),
@@ -1081,6 +1042,10 @@ fn initializeStack(self: *Self) !void {
     assert(self.initial_stack_value == .none);
     // reserve space for immediate value
     // get stack pointer global
+    // TODO: For now, we hardcode the stack pointer to index '0',
+    // once the linker is further implemented, we can replace this by inserting
+    // a relocation and have the linker resolve the correct index to the stack pointer global.
+    // NOTE: relocations of the type GLOBAL_INDEX_LEB are 5-bytes big
     try self.addLabel(.global_get, 0);
 
     // Reserve a local to store the current stack pointer
@@ -1109,6 +1074,8 @@ fn restoreStackPointer(self: *Self) !void {
 /// the result back into the stack pointer.
 fn moveStack(self: *Self, offset: u32, local: u32) !void {
     if (offset == 0) return;
+    // TODO: Rather than hardcode the stack pointer to position 0,
+    // have the linker resolve its relocation
     try self.addLabel(.global_get, 0);
     try self.addImm32(@bitCast(i32, offset));
     try self.addTag(.i32_sub);
@@ -1116,13 +1083,6 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
     try self.addLabel(.global_set, 0);
 }
 
-/// From given zig bitsize, returns the wasm bitsize
-fn toWasmIntBits(bits: u16) ?u16 {
-    return for ([_]u16{ 32, 64 }) |wasm_bits| {
-        if (bits <= wasm_bits) return wasm_bits;
-    } else null;
-}
-
 fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
     const air_tags = self.air.instructions.items(.tag);
     return switch (air_tags[inst]) {
@@ -1169,15 +1129,11 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .load => self.airLoad(inst),
         .loop => self.airLoop(inst),
         .not => self.airNot(inst),
-        .optional_payload => self.airOptionalPayload(inst),
-        .optional_payload_ptr => self.airOptionalPayload(inst),
-        .optional_payload_ptr_set => self.airOptionalPayloadPtrSet(inst),
         .ret => self.airRet(inst),
         .ret_ptr => self.airRetPtr(inst),
         .ret_load => self.airRetLoad(inst),
         .slice_len => self.airSliceLen(inst),
         .slice_elem_val => self.airSliceElemVal(inst),
-        .slice_ptr => self.airSlicePtr(inst),
         .store => self.airStore(inst),
         .struct_field_ptr => self.airStructFieldPtr(inst),
         .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),
@@ -1186,14 +1142,16 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),
         .struct_field_val => self.airStructFieldVal(inst),
         .switch_br => self.airSwitchBr(inst),
-        .trunc => self.airTrunc(inst),
         .unreach => self.airUnreachable(inst),
-
         .wrap_optional => self.airWrapOptional(inst),
+
         .unwrap_errunion_payload => self.airUnwrapErrUnionPayload(inst),
         .unwrap_errunion_err => self.airUnwrapErrUnionError(inst),
         .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),
-        .wrap_errunion_err => self.airWrapErrUnionErr(inst),
+
+        .optional_payload => self.airOptionalPayload(inst),
+        .optional_payload_ptr => self.airOptionalPayload(inst),
+        .optional_payload_ptr_set => self.airOptionalPayloadPtrSet(inst),
         else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
     };
 }
@@ -1235,15 +1193,15 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     // local, containing the offset to the stack position
     const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32
     try self.moveStack(@intCast(u32, abi_size), local.local);
+
     return local;
 }
 
 fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const un_op = self.air.instructions.items(.data)[inst].un_op;
     const operand = self.resolveInst(un_op);
-
-    const result = try self.load(operand, self.air.typeOf(un_op).childType(), 0);
-    try self.emitWValue(result);
+    const result = try self.load(operand, self.air.typeOf(un_op), 0);
+    try self.addLabel(.local_get, result.local);
     try self.restoreStackPointer();
     try self.addTag(.@"return");
     return .none;
@@ -1273,25 +1231,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     };
 
     for (args) |arg| {
-        const arg_ref = @intToEnum(Air.Inst.Ref, arg);
-        const arg_val = self.resolveInst(arg_ref);
-
-        const arg_ty = self.air.typeOf(arg_ref);
-        switch (arg_ty.zigTypeTag()) {
-            .Struct, .Pointer, .Optional, .ErrorUnion => {
-                // single pointer can be passed directly
-                if (arg_ty.isSinglePointer() or arg_val != .constant) {
-                    try self.emitWValue(arg_val);
-                    continue;
-                }
-                const abi_size = arg_ty.abiSize(self.target);
-                const arg_local = try self.allocLocal(Type.initTag(.i32));
-                try self.moveStack(@intCast(u32, abi_size), arg_local.local);
-                try self.store(arg_local, arg_val, arg_ty, 0);
-                try self.emitWValue(arg_local);
-            },
-            else => try self.emitWValue(arg_val),
-        }
+        const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg));
+        try self.emitWValue(arg_val);
     }
 
     if (target) |direct| {
@@ -1301,11 +1242,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
         // so load its value onto the stack
         std.debug.assert(ty.zigTypeTag() == .Pointer);
         const operand = self.resolveInst(pl_op.operand);
-        const offset = switch (operand) {
-            .local_with_offset => |with_offset| with_offset.offset,
-            else => @as(u32, 0),
-        };
-        const result = try self.load(operand, fn_ty, offset);
+        try self.emitWValue(operand);
+        const result = try self.load(operand, fn_ty, operand.local_with_offset.offset);
         try self.addLabel(.local_get, result.local);
 
         var fn_type = try self.genFunctype(fn_ty);
@@ -1316,12 +1254,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     }
 
     const ret_ty = fn_ty.fnReturnType();
-    if (!ret_ty.hasCodeGenBits()) return WValue.none;
-
-    const result_local = try self.allocLocal(ret_ty);
-    try self.addLabel(.local_set, result_local.local);
-    // if the result was allocated on the virtual stack, we must load
-    return result_local;
+    switch (ret_ty.zigTypeTag()) {
+        .Void, .NoReturn => return WValue.none,
+        else => {
+            const result_local = try self.allocLocal(ret_ty);
+            try self.addLabel(.local_set, result_local.local);
+            return result_local;
+        },
+    }
 }
 
 fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
@@ -1338,6 +1278,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     // local, containing the offset to the stack position
     const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32
     try self.moveStack(@intCast(u32, abi_size), local.local);
+
     return local;
 }
 
@@ -1387,15 +1328,16 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
                     return;
                 },
                 .local => {
-                    if (payload_ty.hasCodeGenBits()) {
-                        try self.store(lhs, rhs, payload_ty, payload_offset);
-                    }
-                    return try self.store(lhs, rhs, tag_ty, 0);
+                    // Load values from `rhs` stack position and store in `lhs` instead
+                    const tag_local = try self.load(rhs, tag_ty, 0);
+                    const payload_local = try self.load(rhs, payload_ty, payload_offset);
+
+                    try self.store(lhs, tag_local, tag_ty, 0);
+                    return try self.store(lhs, payload_local, payload_ty, payload_offset);
                 },
                 .local_with_offset => |with_offset| {
                     const tag_local = try self.allocLocal(tag_ty);
                     try self.addImm32(0);
-                    try self.addLabel(.local_set, tag_local.local);
                     try self.store(lhs, tag_local, tag_ty, 0);
 
                     return try self.store(
@@ -1424,18 +1366,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
             }
             return;
         },
-        .Pointer => {
-            if (ty.isSlice() and rhs == .constant) {
-                try self.emitWValue(rhs);
-                const len_local = try self.allocLocal(Type.usize);
-                const ptr_local = try self.allocLocal(Type.usize);
-                try self.addLabel(.local_set, len_local.local);
-                try self.addLabel(.local_set, ptr_local.local);
-                try self.store(lhs, ptr_local, Type.usize, 0);
-                try self.store(lhs, len_local, Type.usize, self.target.cpu.arch.ptrBitWidth() / 8);
-                return;
-            }
-        },
         else => {},
     }
     try self.emitWValue(lhs);
@@ -1472,8 +1402,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const operand = self.resolveInst(ty_op.operand);
     const ty = self.air.getRefType(ty_op.ty);
 
-    if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
-
     return switch (ty.zigTypeTag()) {
         .Struct, .ErrorUnion, .Optional, .Pointer => operand, // pass as pointer
         else => switch (operand) {
@@ -1487,10 +1415,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
     // load local's value from memory by its stack position
     try self.emitWValue(operand);
     // Build the opcode with the right bitsize
-    const signedness: std.builtin.Signedness = if (ty.isUnsignedInt() or ty.zigTypeTag() == .ErrorSet)
-        .unsigned
-    else
-        .signed;
+    const signedness: std.builtin.Signedness = if (ty.isUnsignedInt()) .unsigned else .signed;
     // check if we should pass by pointer or value based on ABI size
     // TODO: Implement a way to get ABI values from a given type,
     // that is portable across the backend, rather than copying logic.
@@ -1601,7 +1526,6 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
 }
 
 fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
-    if (val.isUndefDeep()) return self.emitUndefined(ty);
     switch (ty.zigTypeTag()) {
         .Int => {
             const int_info = ty.intInfo(self.target);
@@ -1629,21 +1553,10 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
             }
         },
         .Pointer => {
-            if (val.castTag(.slice)) |slice| {
-                var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                try self.emitConstant(slice.data.ptr, ty.slicePtrFieldType(&buf));
-                try self.emitConstant(slice.data.len, Type.usize);
-            } else if (val.castTag(.decl_ref)) |payload| {
+            if (val.castTag(.decl_ref)) |payload| {
                 const decl = payload.data;
                 decl.alive = true;
-                // Function pointers use a table index, rather than a memory address
-                if (decl.ty.zigTypeTag() == .Fn) {
-                    const target_sym_index = decl.link.wasm.sym_index;
-                    try self.bin_file.addTableFunction(target_sym_index);
-                    try self.addLabel(.function_index, target_sym_index);
-                } else {
-                    try self.addLabel(.memory_address, decl.link.wasm.sym_index);
-                }
+                try self.addLabel(.memory_address, decl.link.wasm.sym_index);
             } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
         },
         .Void => {},
@@ -1718,22 +1631,6 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
     }
 }
 
-fn emitUndefined(self: *Self, ty: Type) InnerError!void {
-    switch (ty.zigTypeTag()) {
-        .Int => switch (ty.intInfo(self.target).bits) {
-            0...32 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),
-            33...64 => try self.addImm64(0xaaaaaaaaaaaaaaaa),
-            else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),
-        },
-        .Float => switch (ty.floatBits(self.target)) {
-            0...32 => try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) } }),
-            33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),
-            else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),
-        },
-        else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
-    }
-}
-
 /// Returns a `Value` as a signed 32 bit value.
 /// It's illegal to provide a value with a type that cannot be represented
 /// as an integer value.
@@ -1884,7 +1781,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
     });
     try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
 
-    const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
+    const cmp_tmp = try self.allocLocal(lhs_ty);
     try self.addLabel(.local_set, cmp_tmp.local);
     return cmp_tmp;
 }
@@ -2184,25 +2081,9 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
 }
 
 fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
-    if (self.liveness.isUnused(inst)) return WValue.none;
-    const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    const operand = self.resolveInst(ty_op.operand);
-
-    const op_ty = self.air.typeOf(ty_op.operand);
-    if (!op_ty.hasCodeGenBits()) return WValue.none;
-    const err_ty = self.air.getRefType(ty_op.ty);
-    const offset = err_ty.errorUnionSet().abiSize(self.target);
-
-    return WValue{ .local_with_offset = .{
-        .local = operand.local,
-        .offset = @intCast(u32, offset),
-    } };
-}
-
-fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
-    if (self.liveness.isUnused(inst)) return WValue.none;
     const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    return self.resolveInst(ty_op.operand);
+    _ = ty_op;
+    return self.fail("TODO: wasm airWrapErrUnionPayload", .{});
 }
 
 fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
@@ -2211,26 +2092,20 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const operand = self.resolveInst(ty_op.operand);
     const ref_ty = self.air.typeOf(ty_op.operand);
     const ref_info = ref_ty.intInfo(self.target);
-    const wanted_info = ty.intInfo(self.target);
+    const op_bits = ref_info.bits;
+    const wanted_bits = ty.intInfo(self.target).bits;
 
-    const op_bits = toWasmIntBits(ref_info.bits) orelse
-        return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{ref_info.bits});
-    const wanted_bits = toWasmIntBits(wanted_info.bits) orelse
-        return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{wanted_info.bits});
-
-    // hot path
-    if (op_bits == wanted_bits) return operand;
-
-    if (op_bits > 32 and wanted_bits == 32) {
+    if (op_bits > 32 and wanted_bits <= 32) {
         try self.emitWValue(operand);
         try self.addTag(.i32_wrap_i64);
-    } else if (op_bits == 32 and wanted_bits > 32) {
+    } else if (op_bits <= 32 and wanted_bits > 32) {
         try self.emitWValue(operand);
         try self.addTag(switch (ref_info.signedness) {
             .signed => .i64_extend_i32_s,
             .unsigned => .i64_extend_i32_u,
         });
-    }
+    } else return operand;
+
     const result = try self.allocLocal(ty);
     try self.addLabel(.local_set, result.local);
     return result;
@@ -2305,7 +2180,19 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const operand = self.resolveInst(ty_op.operand);
     const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8;
 
-    return try self.load(operand, Type.usize, pointer_width);
+    // Get pointer to slice
+    try self.emitWValue(operand);
+    // length of slice is stored after the pointer of the slice
+    const extra_index = try self.addExtra(Mir.MemArg{
+        .offset = pointer_width,
+        .alignment = pointer_width,
+    });
+    try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } });
+
+    const result = try self.allocLocal(Type.initTag(.i32)); // pointer is always i32
+    // store slice length in local
+    try self.addLabel(.local_set, result.local);
+    return result;
 }
 
 fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
@@ -2319,8 +2206,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const elem_size = elem_ty.abiSize(self.target);
 
     // load pointer onto stack
-    const slice_ptr = try self.load(slice, slice_ty, 0);
-    try self.addLabel(.local_get, slice_ptr.local);
+    try self.emitWValue(slice);
 
     // calculate index into slice
     try self.emitWValue(index);
@@ -2328,79 +2214,25 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     try self.addTag(.i32_mul);
     try self.addTag(.i32_add);
 
-    const result = try self.allocLocal(elem_ty);
-    try self.addLabel(.local_set, result.local);
-    return switch (elem_ty.zigTypeTag()) {
-        // pass as pointer
-        .Pointer, .Struct, .Optional => result,
-        // pass by value
-        else => try self.load(result, elem_ty, 0),
-    };
-}
-
-fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
-    if (self.liveness.isUnused(inst)) return WValue.none;
-    const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    const operand = self.resolveInst(ty_op.operand);
-    return try self.load(operand, Type.usize, 0);
-}
-
-fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
-    if (self.liveness.isUnused(inst)) return WValue.none;
-    const ty_op = self.air.instructions.items(.data)[inst].ty_op;
-    const operand = self.resolveInst(ty_op.operand);
-    const op_ty = self.air.typeOf(ty_op.operand);
-    const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);
-    const wanted_bits = int_info.bits;
-    const result = try self.allocLocal(self.air.getRefType(ty_op.ty));
-    const op_bits = op_ty.intInfo(self.target).bits;
-
-    const wasm_bits = toWasmIntBits(wanted_bits) orelse
-        return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{wanted_bits});
-
-    // Use wasm's instruction to wrap from 64bit to 32bit integer when possible
-    if (op_bits == 64 and wanted_bits == 32) {
-        try self.emitWValue(operand);
-        try self.addTag(.i32_wrap_i64);
-        try self.addLabel(.local_set, result.local);
-        return result;
-    }
+    const abi_size = if (elem_size < 8)
+        @intCast(u8, elem_size)
+    else
+        @as(u8, 4); // elements larger than 8 bytes will be passed by pointer
 
-    // Any other truncation must be done manually
-    if (int_info.signedness == .unsigned) {
-        const mask = (@as(u65, 1) << @intCast(u7, wanted_bits)) - 1;
-        try self.emitWValue(operand);
-        switch (wasm_bits) {
-            32 => {
-                try self.addImm32(@bitCast(i32, @intCast(u32, mask)));
-                try self.addTag(.i32_and);
-            },
-            64 => {
-                try self.addImm64(@intCast(u64, mask));
-                try self.addTag(.i64_and);
-            },
-            else => unreachable,
-        }
-    } else {
-        const shift_bits = wasm_bits - wanted_bits;
-        try self.emitWValue(operand);
-        switch (wasm_bits) {
-            32 => {
-                try self.addImm32(@bitCast(i16, shift_bits));
-                try self.addTag(.i32_shl);
-                try self.addImm32(@bitCast(i16, shift_bits));
-                try self.addTag(.i32_shr_s);
-            },
-            64 => {
-                try self.addImm64(shift_bits);
-                try self.addTag(.i64_shl);
-                try self.addImm64(shift_bits);
-                try self.addTag(.i64_shr_s);
-            },
-            else => unreachable,
-        }
-    }
+    const extra_index = try self.addExtra(Mir.MemArg{
+        .offset = 0,
+        .alignment = elem_ty.abiAlignment(self.target),
+    });
+    const signedness: std.builtin.Signedness = if (elem_ty.isUnsignedInt()) .unsigned else .signed;
+    const opcode = buildOpcode(.{
+        .valtype1 = try self.typeToValtype(elem_ty),
+        .width = abi_size * 8,
+        .op = .load,
+        .signedness = signedness,
+    });
+    try self.addInst(.{ .tag = Mir.Inst.Tag.fromOpcode(opcode), .data = .{ .payload = extra_index } });
 
+    const result = try self.allocLocal(elem_ty);
     try self.addLabel(.local_set, result.local);
     return result;
 }
src/arch/wasm/Emit.zig
@@ -50,7 +50,6 @@ pub fn emitMir(emit: *Emit) InnerError!void {
             .call_indirect => try emit.emitCallIndirect(inst),
             .global_get => try emit.emitGlobal(tag, inst),
             .global_set => try emit.emitGlobal(tag, inst),
-            .function_index => try emit.emitFunctionIndex(inst),
             .memory_address => try emit.emitMemAddress(inst),
 
             // immediates
@@ -148,11 +147,6 @@ pub fn emitMir(emit: *Emit) InnerError!void {
             .i64_div_s => try emit.emitTag(tag),
             .i64_div_u => try emit.emitTag(tag),
             .i64_and => try emit.emitTag(tag),
-            .i64_or => try emit.emitTag(tag),
-            .i64_xor => try emit.emitTag(tag),
-            .i64_shl => try emit.emitTag(tag),
-            .i64_shr_s => try emit.emitTag(tag),
-            .i64_shr_u => try emit.emitTag(tag),
             .i32_wrap_i64 => try emit.emitTag(tag),
             .i64_extend_i32_s => try emit.emitTag(tag),
             .i64_extend_i32_u => try emit.emitTag(tag),
@@ -241,7 +235,7 @@ fn emitImm64(emit: *Emit, inst: Mir.Inst.Index) !void {
     const extra_index = emit.mir.instructions.items(.data)[inst].payload;
     const value = emit.mir.extraData(Mir.Imm64, extra_index);
     try emit.code.append(std.wasm.opcode(.i64_const));
-    try leb128.writeILEB128(emit.code.writer(), @bitCast(i64, value.data.toU64()));
+    try leb128.writeULEB128(emit.code.writer(), value.data.toU64());
 }
 
 fn emitFloat32(emit: *Emit, inst: Mir.Inst.Index) !void {
@@ -290,21 +284,6 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
     try leb128.writeULEB128(emit.code.writer(), label);
 }
 
-fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
-    const symbol_index = emit.mir.instructions.items(.data)[inst].label;
-    try emit.code.append(std.wasm.opcode(.i32_const));
-    const index_offset = emit.offset();
-    var buf: [5]u8 = undefined;
-    leb128.writeUnsignedFixed(5, &buf, symbol_index);
-    try emit.code.appendSlice(&buf);
-
-    try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
-        .offset = index_offset,
-        .index = symbol_index,
-        .relocation_type = .R_WASM_TABLE_INDEX_SLEB,
-    });
-}
-
 fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
     const symbol_index = emit.mir.instructions.items(.data)[inst].label;
     try emit.code.append(std.wasm.opcode(.i32_const));
src/arch/wasm/Mir.zig
@@ -348,16 +348,6 @@ pub const Inst = struct {
         /// Uses `tag`
         i64_and = 0x83,
         /// Uses `tag`
-        i64_or = 0x84,
-        /// Uses `tag`
-        i64_xor = 0x85,
-        /// Uses `tag`
-        i64_shl = 0x86,
-        /// Uses `tag`
-        i64_shr_s = 0x87,
-        /// Uses `tag`
-        i64_shr_u = 0x88,
-        /// Uses `tag`
         i32_wrap_i64 = 0xA7,
         /// Uses `tag`
         i64_extend_i32_s = 0xAC,
@@ -373,17 +363,11 @@ pub const Inst = struct {
         i64_extend16_s = 0xC3,
         /// Uses `tag`
         i64_extend32_s = 0xC4,
-        /// Contains a symbol to a function pointer
-        /// uses `label`
-        ///
-        /// Note: This uses `0xFE` as value as it is unused and not reserved
-        /// by the wasm specification, making it safe to use.
-        function_index = 0xFE,
         /// Contains a symbol to a memory address
         /// Uses `label`
         ///
-        /// Note: This uses `0xFF` as value as it is unused and not reserved
-        /// by the wasm specification, making it safe to use.
+        /// Note: This uses `0xFF` as value as it is unused and not-reserved
+        /// by the wasm specification, making it safe to use
         memory_address = 0xFF,
 
         /// From a given wasm opcode, returns a MIR tag.
src/link/Wasm.zig
@@ -162,8 +162,9 @@ pub fn deinit(self: *Wasm) void {
         decl.link.wasm.deinit(self.base.allocator);
     }
 
-    for (self.func_types.items) |*func_type| {
-        func_type.deinit(self.base.allocator);
+    for (self.func_types.items) |func_type| {
+        self.base.allocator.free(func_type.params);
+        self.base.allocator.free(func_type.returns);
     }
     for (self.segment_info.items) |segment_info| {
         self.base.allocator.free(segment_info.name);
@@ -277,7 +278,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
     defer codegen.deinit();
 
     // generate the 'code' section for the function declaration
-    const result = codegen.genDecl() catch |err| switch (err) {
+    const result = codegen.genDecl(decl.ty, decl.val) catch |err| switch (err) {
         error.CodegenFail => {
             decl.analysis = .codegen_failure;
             try module.failed_decls.put(module.gpa, decl, codegen.err_msg);
@@ -297,7 +298,6 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
 
     if (decl.isExtern()) {
         try self.addOrUpdateImport(decl);
-        return;
     }
 
     if (code.len == 0) return;
@@ -574,6 +574,7 @@ fn resetState(self: *Wasm) void {
     self.segments.clearRetainingCapacity();
     self.segment_info.clearRetainingCapacity();
     self.data_segments.clearRetainingCapacity();
+    self.function_table.clearRetainingCapacity();
     self.atoms.clearRetainingCapacity();
     self.code_section_index = null;
 }
@@ -683,16 +684,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
         );
     }
 
-    // Table section
     if (self.function_table.count() > 0) {
         const header_offset = try reserveVecSectionHeader(file);
         const writer = file.writer();
 
         try leb.writeULEB128(writer, wasm.reftype(.funcref));
-        try emitLimits(writer, .{
-            .min = @intCast(u32, self.function_table.count()),
-            .max = null,
-        });
+        try emitLimits(writer, .{ .min = 1, .max = null });
 
         try writeVecSectionHeader(
             file,
src/Module.zig
@@ -1226,20 +1226,19 @@ pub const Fn = struct {
     };
 
     pub fn deinit(func: *Fn, gpa: Allocator) void {
-        if (func.getInferredErrorSet()) |error_set_data| {
-            error_set_data.map.deinit(gpa);
-            error_set_data.functions.deinit(gpa);
+        if (func.getInferredErrorSet()) |map| {
+            map.deinit(gpa);
         }
     }
 
-    pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data {
+    pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {
         const ret_ty = func.owner_decl.ty.fnReturnType();
         if (ret_ty.tag() == .generic_poison) {
             return null;
         }
         if (ret_ty.zigTypeTag() == .ErrorUnion) {
             if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
-                return &payload.data;
+                return &payload.data.map;
             }
         }
         return null;
@@ -1302,7 +1301,6 @@ pub const Namespace = struct {
             key.destroy(mod);
         }
         anon_decls.deinit(gpa);
-        ns.usingnamespace_set.deinit(gpa);
     }
 
     pub fn deleteAllDecls(
@@ -1334,8 +1332,6 @@ pub const Namespace = struct {
             child_decl.destroy(mod);
         }
         anon_decls.deinit(gpa);
-
-        ns.usingnamespace_set.deinit(gpa);
     }
 
     // This renders e.g. "std.fs.Dir.OpenOptions"
test/behavior.zig
@@ -1,202 +1,198 @@
 const builtin = @import("builtin");
 
 test {
-    // Tests that pass for stage1, stage2, the C -and wasm backend.
+    // Tests that pass for stage1, stage2, and the C backend.
+    _ = @import("behavior/align.zig");
     _ = @import("behavior/basic.zig");
     _ = @import("behavior/bitcast.zig");
+    _ = @import("behavior/bool.zig");
     _ = @import("behavior/bugs/624.zig");
     _ = @import("behavior/bugs/655.zig");
     _ = @import("behavior/bugs/679.zig");
+    _ = @import("behavior/bugs/704.zig");
     _ = @import("behavior/bugs/1111.zig");
     _ = @import("behavior/bugs/1486.zig");
     _ = @import("behavior/bugs/2346.zig");
+    _ = @import("behavior/bugs/2692.zig");
+    _ = @import("behavior/bugs/2889.zig");
+    _ = @import("behavior/bugs/3046.zig");
+    _ = @import("behavior/bugs/3586.zig");
+    _ = @import("behavior/bugs/4560.zig");
+    _ = @import("behavior/bugs/4769_a.zig");
+    _ = @import("behavior/bugs/4769_b.zig");
+    _ = @import("behavior/bugs/4954.zig");
     _ = @import("behavior/bugs/6850.zig");
+    _ = @import("behavior/byval_arg_var.zig");
+    _ = @import("behavior/call.zig");
+    _ = @import("behavior/cast.zig");
+    _ = @import("behavior/defer.zig");
     _ = @import("behavior/enum.zig");
+    _ = @import("behavior/error.zig");
+    _ = @import("behavior/fn_in_struct_in_comptime.zig");
+    _ = @import("behavior/generics.zig");
     _ = @import("behavior/hasdecl.zig");
     _ = @import("behavior/hasfield.zig");
+    _ = @import("behavior/if.zig");
     _ = @import("behavior/import.zig");
+    _ = @import("behavior/incomplete_struct_param_tld.zig");
+    _ = @import("behavior/int128.zig");
+    _ = @import("behavior/inttoptr.zig");
+    _ = @import("behavior/member_func.zig");
+    _ = @import("behavior/null.zig");
+    _ = @import("behavior/optional.zig");
+    _ = @import("behavior/pointers.zig");
+    _ = @import("behavior/ptrcast.zig");
     _ = @import("behavior/pub_enum.zig");
+    _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
     _ = @import("behavior/slice_sentinel_comptime.zig");
+    _ = @import("behavior/struct.zig");
+    _ = @import("behavior/this.zig");
+    _ = @import("behavior/translate_c_macros.zig");
     _ = @import("behavior/truncate.zig");
+    _ = @import("behavior/underscore.zig");
     _ = @import("behavior/usingnamespace.zig");
+    _ = @import("behavior/while.zig");
 
-    // Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend
-    if (!builtin.zig_is_stage2 or (builtin.zig_is_stage2 and builtin.stage2_arch != .wasm32)) {
-        _ = @import("behavior/align.zig");
-        _ = @import("behavior/bool.zig");
-        _ = @import("behavior/bugs/704.zig");
-        _ = @import("behavior/bugs/2692.zig");
-        _ = @import("behavior/bugs/2889.zig");
-        _ = @import("behavior/bugs/3046.zig");
-        _ = @import("behavior/bugs/3586.zig");
-        _ = @import("behavior/bugs/4560.zig");
-        _ = @import("behavior/bugs/4769_a.zig");
-        _ = @import("behavior/bugs/4769_b.zig");
-        _ = @import("behavior/bugs/4954.zig");
-        _ = @import("behavior/byval_arg_var.zig");
-        _ = @import("behavior/call.zig");
-        _ = @import("behavior/cast.zig");
-        _ = @import("behavior/defer.zig");
-        _ = @import("behavior/error.zig");
-        _ = @import("behavior/fn_in_struct_in_comptime.zig");
-        _ = @import("behavior/generics.zig");
-        _ = @import("behavior/if.zig");
-        _ = @import("behavior/incomplete_struct_param_tld.zig");
-        _ = @import("behavior/int128.zig");
-        _ = @import("behavior/inttoptr.zig");
-        _ = @import("behavior/member_func.zig");
-        _ = @import("behavior/null.zig");
-        _ = @import("behavior/optional.zig");
-        _ = @import("behavior/pointers.zig");
-        _ = @import("behavior/ptrcast.zig");
-        _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
-        _ = @import("behavior/struct.zig");
-        _ = @import("behavior/this.zig");
-        _ = @import("behavior/translate_c_macros.zig");
-        _ = @import("behavior/underscore.zig");
-        _ = @import("behavior/while.zig");
+    if (builtin.object_format != .c) {
+        // Tests that pass for stage1 and stage2 but not the C backend.
+        _ = @import("behavior/align_llvm.zig");
+        _ = @import("behavior/alignof.zig");
+        _ = @import("behavior/array.zig");
+        _ = @import("behavior/atomics.zig");
+        _ = @import("behavior/basic_llvm.zig");
+        _ = @import("behavior/bugs/394.zig");
+        _ = @import("behavior/bugs/656.zig");
+        _ = @import("behavior/bugs/1277.zig");
+        _ = @import("behavior/bugs/1381.zig");
+        _ = @import("behavior/bugs/1500.zig");
+        _ = @import("behavior/bugs/1741.zig");
+        _ = @import("behavior/bugs/2006.zig");
+        _ = @import("behavior/bugs/2578.zig");
+        _ = @import("behavior/bugs/3007.zig");
+        _ = @import("behavior/bugs/3112.zig");
+        _ = @import("behavior/bugs/7250.zig");
+        _ = @import("behavior/cast_llvm.zig");
+        _ = @import("behavior/eval.zig");
+        _ = @import("behavior/floatop.zig");
+        _ = @import("behavior/fn.zig");
+        _ = @import("behavior/for.zig");
+        _ = @import("behavior/generics_llvm.zig");
+        _ = @import("behavior/math.zig");
+        _ = @import("behavior/maximum_minimum.zig");
+        _ = @import("behavior/namespace_depends_on_compile_var.zig");
+        _ = @import("behavior/null_llvm.zig");
+        _ = @import("behavior/optional_llvm.zig");
+        _ = @import("behavior/popcount.zig");
+        _ = @import("behavior/saturating_arithmetic.zig");
+        _ = @import("behavior/sizeof_and_typeof.zig");
+        _ = @import("behavior/slice.zig");
+        _ = @import("behavior/struct_llvm.zig");
+        _ = @import("behavior/switch.zig");
+        _ = @import("behavior/undefined.zig");
+        _ = @import("behavior/union.zig");
+        _ = @import("behavior/void.zig");
+        _ = @import("behavior/widening.zig");
 
-        if (builtin.object_format != .c) {
-            // Tests that pass for stage1 and stage2 but not the C backend and wasm backend.
-            _ = @import("behavior/align_llvm.zig");
-            _ = @import("behavior/alignof.zig");
-            _ = @import("behavior/array.zig");
-            _ = @import("behavior/atomics.zig");
-            _ = @import("behavior/basic_llvm.zig");
-            _ = @import("behavior/bugs/394.zig");
-            _ = @import("behavior/bugs/656.zig");
-            _ = @import("behavior/bugs/1277.zig");
-            _ = @import("behavior/bugs/1381.zig");
-            _ = @import("behavior/bugs/1500.zig");
-            _ = @import("behavior/bugs/1741.zig");
-            _ = @import("behavior/bugs/2006.zig");
-            _ = @import("behavior/bugs/2578.zig");
-            _ = @import("behavior/bugs/3007.zig");
-            _ = @import("behavior/bugs/3112.zig");
-            _ = @import("behavior/bugs/7250.zig");
-            _ = @import("behavior/cast_llvm.zig");
-            _ = @import("behavior/eval.zig");
-            _ = @import("behavior/floatop.zig");
-            _ = @import("behavior/fn.zig");
-            _ = @import("behavior/for.zig");
-            _ = @import("behavior/generics_llvm.zig");
-            _ = @import("behavior/math.zig");
-            _ = @import("behavior/maximum_minimum.zig");
-            _ = @import("behavior/namespace_depends_on_compile_var.zig");
-            _ = @import("behavior/null_llvm.zig");
-            _ = @import("behavior/optional_llvm.zig");
-            _ = @import("behavior/popcount.zig");
-            _ = @import("behavior/saturating_arithmetic.zig");
-            _ = @import("behavior/sizeof_and_typeof.zig");
-            _ = @import("behavior/slice.zig");
-            _ = @import("behavior/struct_llvm.zig");
-            _ = @import("behavior/switch.zig");
-            _ = @import("behavior/undefined.zig");
-            _ = @import("behavior/union.zig");
-            _ = @import("behavior/void.zig");
-            _ = @import("behavior/widening.zig");
-
-            if (builtin.zig_is_stage2) {
-                // When all comptime_memory.zig tests pass, #9646 can be closed.
-                // _ = @import("behavior/comptime_memory.zig");
-                _ = @import("behavior/slice_stage2.zig");
-            } else {
-                _ = @import("behavior/align_stage1.zig");
-                _ = @import("behavior/array_stage1.zig");
-                if (builtin.os.tag != .wasi) {
-                    _ = @import("behavior/asm.zig");
-                    _ = @import("behavior/async_fn.zig");
-                }
-                _ = @import("behavior/await_struct.zig");
-                _ = @import("behavior/bit_shifting.zig");
-                _ = @import("behavior/bitcast_stage1.zig");
-                _ = @import("behavior/bitreverse.zig");
-                _ = @import("behavior/bugs/421.zig");
-                _ = @import("behavior/bugs/529.zig");
-                _ = @import("behavior/bugs/718.zig");
-                _ = @import("behavior/bugs/726.zig");
-                _ = @import("behavior/bugs/828.zig");
-                _ = @import("behavior/bugs/920.zig");
-                _ = @import("behavior/bugs/1025.zig");
-                _ = @import("behavior/bugs/1076.zig");
-                _ = @import("behavior/bugs/1120.zig");
-                _ = @import("behavior/bugs/1310.zig");
-                _ = @import("behavior/bugs/1322.zig");
-                _ = @import("behavior/bugs/1421.zig");
-                _ = @import("behavior/bugs/1442.zig");
-                _ = @import("behavior/bugs/1607.zig");
-                _ = @import("behavior/bugs/1735.zig");
-                _ = @import("behavior/bugs/1851.zig");
-                _ = @import("behavior/bugs/1914.zig");
-                _ = @import("behavior/bugs/2114.zig");
-                _ = @import("behavior/bugs/3367.zig");
-                _ = @import("behavior/bugs/3384.zig");
-                _ = @import("behavior/bugs/3742.zig");
-                _ = @import("behavior/bugs/3779.zig");
-                _ = @import("behavior/bugs/4328.zig");
-                _ = @import("behavior/bugs/5398.zig");
-                _ = @import("behavior/bugs/5413.zig");
-                _ = @import("behavior/bugs/5474.zig");
-                _ = @import("behavior/bugs/5487.zig");
-                _ = @import("behavior/bugs/6456.zig");
-                _ = @import("behavior/bugs/6781.zig");
-                _ = @import("behavior/bugs/7003.zig");
-                _ = @import("behavior/bugs/7027.zig");
-                _ = @import("behavior/bugs/7047.zig");
-                _ = @import("behavior/bugs/9584.zig");
-                _ = @import("behavior/bugs/9967.zig");
-                _ = @import("behavior/bugs/10147.zig");
-                _ = @import("behavior/byteswap.zig");
-                _ = @import("behavior/call_stage1.zig");
-                _ = @import("behavior/cast_stage1.zig");
-                _ = @import("behavior/const_slice_child.zig");
-                _ = @import("behavior/defer_stage1.zig");
-                _ = @import("behavior/enum_stage1.zig");
-                _ = @import("behavior/error_stage1.zig");
-                _ = @import("behavior/eval_stage1.zig");
-                _ = @import("behavior/field_parent_ptr.zig");
-                _ = @import("behavior/floatop_stage1.zig");
-                _ = @import("behavior/fn_stage1.zig");
-                _ = @import("behavior/fn_delegation.zig");
-                _ = @import("behavior/for_stage1.zig");
-                _ = @import("behavior/if_stage1.zig");
-                _ = @import("behavior/ir_block_deps.zig");
-                _ = @import("behavior/math_stage1.zig");
-                _ = @import("behavior/merge_error_sets.zig");
-                _ = @import("behavior/misc.zig");
-                _ = @import("behavior/muladd.zig");
-                _ = @import("behavior/null_stage1.zig");
-                _ = @import("behavior/optional_stage1.zig");
-                _ = @import("behavior/pointers_stage1.zig");
-                _ = @import("behavior/popcount_stage1.zig");
-                _ = @import("behavior/ptrcast_stage1.zig");
-                _ = @import("behavior/reflection.zig");
-                _ = @import("behavior/select.zig");
-                _ = @import("behavior/shuffle.zig");
-                _ = @import("behavior/sizeof_and_typeof_stage1.zig");
-                _ = @import("behavior/slice_stage1.zig");
-                _ = @import("behavior/struct_contains_null_ptr_itself.zig");
-                _ = @import("behavior/struct_contains_slice_of_itself.zig");
-                _ = @import("behavior/struct_stage1.zig");
-                _ = @import("behavior/switch_prong_err_enum.zig");
-                _ = @import("behavior/switch_prong_implicit_cast.zig");
-                _ = @import("behavior/switch_stage1.zig");
-                _ = @import("behavior/try.zig");
-                _ = @import("behavior/tuple.zig");
-                _ = @import("behavior/type.zig");
-                _ = @import("behavior/type_info.zig");
-                _ = @import("behavior/typename.zig");
-                _ = @import("behavior/union_stage1.zig");
-                _ = @import("behavior/union_with_members.zig");
-                _ = @import("behavior/var_args.zig");
-                _ = @import("behavior/vector.zig");
-                if (builtin.target.cpu.arch == .wasm32) {
-                    _ = @import("behavior/wasm.zig");
-                }
-                _ = @import("behavior/while_stage1.zig");
-                _ = @import("behavior/src.zig");
-                _ = @import("behavior/translate_c_macros_stage1.zig");
+        if (builtin.zig_is_stage2) {
+            // When all comptime_memory.zig tests pass, #9646 can be closed.
+            // _ = @import("behavior/comptime_memory.zig");
+            _ = @import("behavior/slice_stage2.zig");
+        } else {
+            _ = @import("behavior/align_stage1.zig");
+            _ = @import("behavior/array_stage1.zig");
+            if (builtin.os.tag != .wasi) {
+                _ = @import("behavior/asm.zig");
+                _ = @import("behavior/async_fn.zig");
+            }
+            _ = @import("behavior/await_struct.zig");
+            _ = @import("behavior/bit_shifting.zig");
+            _ = @import("behavior/bitcast_stage1.zig");
+            _ = @import("behavior/bitreverse.zig");
+            _ = @import("behavior/bugs/421.zig");
+            _ = @import("behavior/bugs/529.zig");
+            _ = @import("behavior/bugs/718.zig");
+            _ = @import("behavior/bugs/726.zig");
+            _ = @import("behavior/bugs/828.zig");
+            _ = @import("behavior/bugs/920.zig");
+            _ = @import("behavior/bugs/1025.zig");
+            _ = @import("behavior/bugs/1076.zig");
+            _ = @import("behavior/bugs/1120.zig");
+            _ = @import("behavior/bugs/1310.zig");
+            _ = @import("behavior/bugs/1322.zig");
+            _ = @import("behavior/bugs/1421.zig");
+            _ = @import("behavior/bugs/1442.zig");
+            _ = @import("behavior/bugs/1607.zig");
+            _ = @import("behavior/bugs/1735.zig");
+            _ = @import("behavior/bugs/1851.zig");
+            _ = @import("behavior/bugs/1914.zig");
+            _ = @import("behavior/bugs/2114.zig");
+            _ = @import("behavior/bugs/3367.zig");
+            _ = @import("behavior/bugs/3384.zig");
+            _ = @import("behavior/bugs/3742.zig");
+            _ = @import("behavior/bugs/3779.zig");
+            _ = @import("behavior/bugs/4328.zig");
+            _ = @import("behavior/bugs/5398.zig");
+            _ = @import("behavior/bugs/5413.zig");
+            _ = @import("behavior/bugs/5474.zig");
+            _ = @import("behavior/bugs/5487.zig");
+            _ = @import("behavior/bugs/6456.zig");
+            _ = @import("behavior/bugs/6781.zig");
+            _ = @import("behavior/bugs/7003.zig");
+            _ = @import("behavior/bugs/7027.zig");
+            _ = @import("behavior/bugs/7047.zig");
+            _ = @import("behavior/bugs/9584.zig");
+            _ = @import("behavior/bugs/9967.zig");
+            _ = @import("behavior/bugs/10147.zig");
+            _ = @import("behavior/byteswap.zig");
+            _ = @import("behavior/call_stage1.zig");
+            _ = @import("behavior/cast_stage1.zig");
+            _ = @import("behavior/const_slice_child.zig");
+            _ = @import("behavior/defer_stage1.zig");
+            _ = @import("behavior/enum_stage1.zig");
+            _ = @import("behavior/error_stage1.zig");
+            _ = @import("behavior/eval_stage1.zig");
+            _ = @import("behavior/field_parent_ptr.zig");
+            _ = @import("behavior/floatop_stage1.zig");
+            _ = @import("behavior/fn_stage1.zig");
+            _ = @import("behavior/fn_delegation.zig");
+            _ = @import("behavior/for_stage1.zig");
+            _ = @import("behavior/if_stage1.zig");
+            _ = @import("behavior/ir_block_deps.zig");
+            _ = @import("behavior/math_stage1.zig");
+            _ = @import("behavior/merge_error_sets.zig");
+            _ = @import("behavior/misc.zig");
+            _ = @import("behavior/muladd.zig");
+            _ = @import("behavior/null_stage1.zig");
+            _ = @import("behavior/optional_stage1.zig");
+            _ = @import("behavior/pointers_stage1.zig");
+            _ = @import("behavior/popcount_stage1.zig");
+            _ = @import("behavior/ptrcast_stage1.zig");
+            _ = @import("behavior/reflection.zig");
+            _ = @import("behavior/select.zig");
+            _ = @import("behavior/shuffle.zig");
+            _ = @import("behavior/sizeof_and_typeof_stage1.zig");
+            _ = @import("behavior/slice_stage1.zig");
+            _ = @import("behavior/struct_contains_null_ptr_itself.zig");
+            _ = @import("behavior/struct_contains_slice_of_itself.zig");
+            _ = @import("behavior/struct_stage1.zig");
+            _ = @import("behavior/switch_prong_err_enum.zig");
+            _ = @import("behavior/switch_prong_implicit_cast.zig");
+            _ = @import("behavior/switch_stage1.zig");
+            _ = @import("behavior/try.zig");
+            _ = @import("behavior/tuple.zig");
+            _ = @import("behavior/type.zig");
+            _ = @import("behavior/type_info.zig");
+            _ = @import("behavior/typename.zig");
+            _ = @import("behavior/union_stage1.zig");
+            _ = @import("behavior/union_with_members.zig");
+            _ = @import("behavior/var_args.zig");
+            _ = @import("behavior/vector.zig");
+            if (builtin.target.cpu.arch == .wasm32) {
+                _ = @import("behavior/wasm.zig");
             }
+            _ = @import("behavior/while_stage1.zig");
+            _ = @import("behavior/src.zig");
+            _ = @import("behavior/translate_c_macros_stage1.zig");
         }
     }
 }