Commit aecebf38ac

Andrew Kelley <andrew@ziglang.org>
2021-09-22 07:33:00
stage2: progress towards ability to compile compiler-rt
* prepare compiler-rt to support being compiled by stage2 - put in a few minor workarounds that will be removed later, such as using `builtin.stage2_arch` rather than `builtin.cpu.arch`. - only try to export a few symbols for now - we'll move more symbols over to the "working in stage2" section as they become functional and gain test coverage. - use `inline fn` at function declarations rather than `@call` with an always_inline modifier at the callsites, to avoid depending on the anonymous array literal syntax language feature (for now). * AIR: replace floatcast instruction with fptrunc and fpext for shortening and widening floating point values, respectively. * Introduce a new ZIR instruction, `export_value`, which implements `@export` for the case when the thing to be exported is a local comptime value that points to a function. - AstGen: fix `@export` not properly reporting ambiguous decl references. * Sema: handle ExportOptions linkage. The value is now available to all backends. - Implement setting global linkage as appropriate in the LLVM backend. I did not yet inspect the LLVM IR, so this still needs to be audited. There is already a pending task to make sure the alias stuff is working as intended, and this is related. - Sema almost handles section, just a tiny bit more code is needed in `resolveExportOptions`. * Sema: implement float widening and shortening for both `@floatCast` and float coercion. - Implement the LLVM backend code for this as well.
1 parent 0e2b9ac
lib/std/special/compiler_rt/extendXfYf2.zig
@@ -3,23 +3,23 @@ const builtin = @import("builtin");
 const is_test = builtin.is_test;
 
 pub fn __extendsfdf2(a: f32) callconv(.C) f64 {
-    return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, a) });
+    return extendXfYf2(f64, f32, @bitCast(u32, a));
 }
 
 pub fn __extenddftf2(a: f64) callconv(.C) f128 {
-    return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f64, @bitCast(u64, a) });
+    return extendXfYf2(f128, f64, @bitCast(u64, a));
 }
 
 pub fn __extendsftf2(a: f32) callconv(.C) f128 {
-    return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f32, @bitCast(u32, a) });
+    return extendXfYf2(f128, f32, @bitCast(u32, a));
 }
 
 pub fn __extendhfsf2(a: u16) callconv(.C) f32 {
-    return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, a });
+    return extendXfYf2(f32, f16, a);
 }
 
 pub fn __extendhftf2(a: u16) callconv(.C) f128 {
-    return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f16, a });
+    return extendXfYf2(f128, f16, a);
 }
 
 pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 {
@@ -34,7 +34,7 @@ pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 {
 
 const CHAR_BIT = 8;
 
-fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t {
+inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t {
     @setRuntimeSafety(builtin.is_test);
 
     const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits);
lib/std/special/compiler_rt.zig
@@ -1,171 +1,24 @@
 const std = @import("std");
-const builtin = std.builtin;
+const builtin = @import("builtin");
 const is_test = builtin.is_test;
 const os_tag = std.Target.current.os.tag;
-const arch = std.Target.current.cpu.arch;
+const arch = builtin.stage2_arch;
 const abi = std.Target.current.abi;
 
 const is_gnu = abi.isGnu();
 const is_mingw = os_tag == .windows and is_gnu;
 
-comptime {
-    const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
-    const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
-
-    switch (arch) {
-        .i386,
-        .x86_64,
-        => {
-            const zig_probe_stack = @import("compiler_rt/stack_probe.zig").zig_probe_stack;
-            @export(zig_probe_stack, .{
-                .name = "__zig_probe_stack",
-                .linkage = linkage,
-            });
-        },
-
-        else => {},
-    }
+const linkage = if (is_test)
+    std.builtin.GlobalLinkage.Internal
+else
+    std.builtin.GlobalLinkage.Weak;
 
-    // __clear_cache manages its own logic about whether to be exported or not.
-    _ = @import("compiler_rt/clear_cache.zig").clear_cache;
-
-    const __lesf2 = @import("compiler_rt/compareXf2.zig").__lesf2;
-    @export(__lesf2, .{ .name = "__lesf2", .linkage = linkage });
-    const __ledf2 = @import("compiler_rt/compareXf2.zig").__ledf2;
-    @export(__ledf2, .{ .name = "__ledf2", .linkage = linkage });
-    const __letf2 = @import("compiler_rt/compareXf2.zig").__letf2;
-    @export(__letf2, .{ .name = "__letf2", .linkage = linkage });
-
-    const __gesf2 = @import("compiler_rt/compareXf2.zig").__gesf2;
-    @export(__gesf2, .{ .name = "__gesf2", .linkage = linkage });
-    const __gedf2 = @import("compiler_rt/compareXf2.zig").__gedf2;
-    @export(__gedf2, .{ .name = "__gedf2", .linkage = linkage });
-    const __getf2 = @import("compiler_rt/compareXf2.zig").__getf2;
-    @export(__getf2, .{ .name = "__getf2", .linkage = linkage });
-
-    if (!is_test) {
-        @export(__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
-        @export(__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__cmptf2", .linkage = linkage });
-
-        const __eqsf2 = @import("compiler_rt/compareXf2.zig").__eqsf2;
-        @export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
-        const __eqdf2 = @import("compiler_rt/compareXf2.zig").__eqdf2;
-        @export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__eqtf2", .linkage = linkage });
-
-        const __ltsf2 = @import("compiler_rt/compareXf2.zig").__ltsf2;
-        @export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
-        const __ltdf2 = @import("compiler_rt/compareXf2.zig").__ltdf2;
-        @export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__lttf2", .linkage = linkage });
-
-        const __nesf2 = @import("compiler_rt/compareXf2.zig").__nesf2;
-        @export(__nesf2, .{ .name = "__nesf2", .linkage = linkage });
-        const __nedf2 = @import("compiler_rt/compareXf2.zig").__nedf2;
-        @export(__nedf2, .{ .name = "__nedf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__netf2", .linkage = linkage });
-
-        const __gtsf2 = @import("compiler_rt/compareXf2.zig").__gtsf2;
-        @export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
-        const __gtdf2 = @import("compiler_rt/compareXf2.zig").__gtdf2;
-        @export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
-        @export(__getf2, .{ .name = "__gttf2", .linkage = linkage });
-
-        const __extendhfsf2 = @import("compiler_rt/extendXfYf2.zig").__extendhfsf2;
-        @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
-        const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2;
-        @export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
-    }
-
-    const __unordsf2 = @import("compiler_rt/compareXf2.zig").__unordsf2;
-    @export(__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
-    const __unorddf2 = @import("compiler_rt/compareXf2.zig").__unorddf2;
-    @export(__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
-    const __unordtf2 = @import("compiler_rt/compareXf2.zig").__unordtf2;
-    @export(__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
-
-    const __addsf3 = @import("compiler_rt/addXf3.zig").__addsf3;
-    @export(__addsf3, .{ .name = "__addsf3", .linkage = linkage });
-    const __adddf3 = @import("compiler_rt/addXf3.zig").__adddf3;
-    @export(__adddf3, .{ .name = "__adddf3", .linkage = linkage });
-    const __addtf3 = @import("compiler_rt/addXf3.zig").__addtf3;
-    @export(__addtf3, .{ .name = "__addtf3", .linkage = linkage });
-    const __subsf3 = @import("compiler_rt/addXf3.zig").__subsf3;
-    @export(__subsf3, .{ .name = "__subsf3", .linkage = linkage });
-    const __subdf3 = @import("compiler_rt/addXf3.zig").__subdf3;
-    @export(__subdf3, .{ .name = "__subdf3", .linkage = linkage });
-    const __subtf3 = @import("compiler_rt/addXf3.zig").__subtf3;
-    @export(__subtf3, .{ .name = "__subtf3", .linkage = linkage });
-
-    const __mulsf3 = @import("compiler_rt/mulXf3.zig").__mulsf3;
-    @export(__mulsf3, .{ .name = "__mulsf3", .linkage = linkage });
-    const __muldf3 = @import("compiler_rt/mulXf3.zig").__muldf3;
-    @export(__muldf3, .{ .name = "__muldf3", .linkage = linkage });
-    const __multf3 = @import("compiler_rt/mulXf3.zig").__multf3;
-    @export(__multf3, .{ .name = "__multf3", .linkage = linkage });
-
-    const __divsf3 = @import("compiler_rt/divsf3.zig").__divsf3;
-    @export(__divsf3, .{ .name = "__divsf3", .linkage = linkage });
-    const __divdf3 = @import("compiler_rt/divdf3.zig").__divdf3;
-    @export(__divdf3, .{ .name = "__divdf3", .linkage = linkage });
-    const __divtf3 = @import("compiler_rt/divtf3.zig").__divtf3;
-    @export(__divtf3, .{ .name = "__divtf3", .linkage = linkage });
-
-    const __ashldi3 = @import("compiler_rt/shift.zig").__ashldi3;
-    @export(__ashldi3, .{ .name = "__ashldi3", .linkage = linkage });
-    const __ashlti3 = @import("compiler_rt/shift.zig").__ashlti3;
-    @export(__ashlti3, .{ .name = "__ashlti3", .linkage = linkage });
-    const __ashrdi3 = @import("compiler_rt/shift.zig").__ashrdi3;
-    @export(__ashrdi3, .{ .name = "__ashrdi3", .linkage = linkage });
-    const __ashrti3 = @import("compiler_rt/shift.zig").__ashrti3;
-    @export(__ashrti3, .{ .name = "__ashrti3", .linkage = linkage });
-    const __lshrdi3 = @import("compiler_rt/shift.zig").__lshrdi3;
-    @export(__lshrdi3, .{ .name = "__lshrdi3", .linkage = linkage });
-    const __lshrti3 = @import("compiler_rt/shift.zig").__lshrti3;
-    @export(__lshrti3, .{ .name = "__lshrti3", .linkage = linkage });
-
-    const __floatsidf = @import("compiler_rt/floatsiXf.zig").__floatsidf;
-    @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage });
-    const __floatsisf = @import("compiler_rt/floatsiXf.zig").__floatsisf;
-    @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage });
-    const __floatdidf = @import("compiler_rt/floatdidf.zig").__floatdidf;
-    @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage });
-    const __floatsitf = @import("compiler_rt/floatsiXf.zig").__floatsitf;
-    @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage });
-
-    const __floatunsisf = @import("compiler_rt/floatunsisf.zig").__floatunsisf;
-    @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage });
-    const __floatundisf = @import("compiler_rt/floatundisf.zig").__floatundisf;
-    @export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage });
-    const __floatunsidf = @import("compiler_rt/floatunsidf.zig").__floatunsidf;
-    @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage });
-    const __floatundidf = @import("compiler_rt/floatundidf.zig").__floatundidf;
-    @export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage });
-
-    const __floatditf = @import("compiler_rt/floatditf.zig").__floatditf;
-    @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage });
-    const __floattitf = @import("compiler_rt/floattitf.zig").__floattitf;
-    @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage });
-    const __floattidf = @import("compiler_rt/floattidf.zig").__floattidf;
-    @export(__floattidf, .{ .name = "__floattidf", .linkage = linkage });
-    const __floattisf = @import("compiler_rt/floatXisf.zig").__floattisf;
-    @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage });
-    const __floatdisf = @import("compiler_rt/floatXisf.zig").__floatdisf;
-    @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage });
-
-    const __floatunditf = @import("compiler_rt/floatunditf.zig").__floatunditf;
-    @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage });
-    const __floatunsitf = @import("compiler_rt/floatunsitf.zig").__floatunsitf;
-    @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage });
-
-    const __floatuntitf = @import("compiler_rt/floatuntitf.zig").__floatuntitf;
-    @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage });
-    const __floatuntidf = @import("compiler_rt/floatuntidf.zig").__floatuntidf;
-    @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage });
-    const __floatuntisf = @import("compiler_rt/floatuntisf.zig").__floatuntisf;
-    @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage });
+const strong_linkage = if (is_test)
+    std.builtin.GlobalLinkage.Internal
+else
+    std.builtin.GlobalLinkage.Strong;
 
+comptime {
     const __extenddftf2 = @import("compiler_rt/extendXfYf2.zig").__extenddftf2;
     @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage });
     const __extendsftf2 = @import("compiler_rt/extendXfYf2.zig").__extendsftf2;
@@ -175,446 +28,611 @@ comptime {
     const __extendhftf2 = @import("compiler_rt/extendXfYf2.zig").__extendhftf2;
     @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage });
 
-    const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2;
-    @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage });
-    const __truncdfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfhf2;
-    @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage });
-    const __trunctfhf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfhf2;
-    @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage });
-    const __trunctfdf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfdf2;
-    @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage });
-    const __trunctfsf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfsf2;
-    @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage });
-
-    const __truncdfsf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfsf2;
-    @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage });
-
-    const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2;
-    @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage });
-
-    const __fixunssfsi = @import("compiler_rt/fixunssfsi.zig").__fixunssfsi;
-    @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage });
-    const __fixunssfdi = @import("compiler_rt/fixunssfdi.zig").__fixunssfdi;
-    @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage });
-    const __fixunssfti = @import("compiler_rt/fixunssfti.zig").__fixunssfti;
-    @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage });
-
-    const __fixunsdfsi = @import("compiler_rt/fixunsdfsi.zig").__fixunsdfsi;
-    @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage });
-    const __fixunsdfdi = @import("compiler_rt/fixunsdfdi.zig").__fixunsdfdi;
-    @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage });
-    const __fixunsdfti = @import("compiler_rt/fixunsdfti.zig").__fixunsdfti;
-    @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage });
-
-    const __fixunstfsi = @import("compiler_rt/fixunstfsi.zig").__fixunstfsi;
-    @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage });
-    const __fixunstfdi = @import("compiler_rt/fixunstfdi.zig").__fixunstfdi;
-    @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage });
-    const __fixunstfti = @import("compiler_rt/fixunstfti.zig").__fixunstfti;
-    @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage });
-
-    const __fixdfdi = @import("compiler_rt/fixdfdi.zig").__fixdfdi;
-    @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage });
-    const __fixdfsi = @import("compiler_rt/fixdfsi.zig").__fixdfsi;
-    @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage });
-    const __fixdfti = @import("compiler_rt/fixdfti.zig").__fixdfti;
-    @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage });
-    const __fixsfdi = @import("compiler_rt/fixsfdi.zig").__fixsfdi;
-    @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage });
-    const __fixsfsi = @import("compiler_rt/fixsfsi.zig").__fixsfsi;
-    @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage });
-    const __fixsfti = @import("compiler_rt/fixsfti.zig").__fixsfti;
-    @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage });
-    const __fixtfdi = @import("compiler_rt/fixtfdi.zig").__fixtfdi;
-    @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage });
-    const __fixtfsi = @import("compiler_rt/fixtfsi.zig").__fixtfsi;
-    @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage });
-    const __fixtfti = @import("compiler_rt/fixtfti.zig").__fixtfti;
-    @export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage });
-
-    const __udivmoddi4 = @import("compiler_rt/int.zig").__udivmoddi4;
-    @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = linkage });
-    const __popcountdi2 = @import("compiler_rt/popcountdi2.zig").__popcountdi2;
-    @export(__popcountdi2, .{ .name = "__popcountdi2", .linkage = linkage });
-
-    const __mulsi3 = @import("compiler_rt/int.zig").__mulsi3;
-    @export(__mulsi3, .{ .name = "__mulsi3", .linkage = linkage });
-    const __muldi3 = @import("compiler_rt/muldi3.zig").__muldi3;
-    @export(__muldi3, .{ .name = "__muldi3", .linkage = linkage });
-    const __divmoddi4 = @import("compiler_rt/int.zig").__divmoddi4;
-    @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = linkage });
-    const __divsi3 = @import("compiler_rt/int.zig").__divsi3;
-    @export(__divsi3, .{ .name = "__divsi3", .linkage = linkage });
-    const __divdi3 = @import("compiler_rt/int.zig").__divdi3;
-    @export(__divdi3, .{ .name = "__divdi3", .linkage = linkage });
-    const __udivsi3 = @import("compiler_rt/int.zig").__udivsi3;
-    @export(__udivsi3, .{ .name = "__udivsi3", .linkage = linkage });
-    const __udivdi3 = @import("compiler_rt/int.zig").__udivdi3;
-    @export(__udivdi3, .{ .name = "__udivdi3", .linkage = linkage });
-    const __modsi3 = @import("compiler_rt/int.zig").__modsi3;
-    @export(__modsi3, .{ .name = "__modsi3", .linkage = linkage });
-    const __moddi3 = @import("compiler_rt/int.zig").__moddi3;
-    @export(__moddi3, .{ .name = "__moddi3", .linkage = linkage });
-    const __umodsi3 = @import("compiler_rt/int.zig").__umodsi3;
-    @export(__umodsi3, .{ .name = "__umodsi3", .linkage = linkage });
-    const __umoddi3 = @import("compiler_rt/int.zig").__umoddi3;
-    @export(__umoddi3, .{ .name = "__umoddi3", .linkage = linkage });
-    const __divmodsi4 = @import("compiler_rt/int.zig").__divmodsi4;
-    @export(__divmodsi4, .{ .name = "__divmodsi4", .linkage = linkage });
-    const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4;
-    @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage });
-
-    const __negsf2 = @import("compiler_rt/negXf2.zig").__negsf2;
-    @export(__negsf2, .{ .name = "__negsf2", .linkage = linkage });
-    const __negdf2 = @import("compiler_rt/negXf2.zig").__negdf2;
-    @export(__negdf2, .{ .name = "__negdf2", .linkage = linkage });
-
-    const __clzsi2 = @import("compiler_rt/count0bits.zig").__clzsi2;
-    @export(__clzsi2, .{ .name = "__clzsi2", .linkage = linkage });
-    const __clzdi2 = @import("compiler_rt/count0bits.zig").__clzdi2;
-    @export(__clzdi2, .{ .name = "__clzdi2", .linkage = linkage });
-    const __clzti2 = @import("compiler_rt/count0bits.zig").__clzti2;
-    @export(__clzti2, .{ .name = "__clzti2", .linkage = linkage });
-
-    if (builtin.link_libc and os_tag == .openbsd) {
-        const __emutls_get_address = @import("compiler_rt/emutls.zig").__emutls_get_address;
-        @export(__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = linkage });
-    }
+    if (!builtin.zig_is_stage2) {
+        switch (arch) {
+            .i386,
+            .x86_64,
+            => {
+                const zig_probe_stack = @import("compiler_rt/stack_probe.zig").zig_probe_stack;
+                @export(zig_probe_stack, .{
+                    .name = "__zig_probe_stack",
+                    .linkage = linkage,
+                });
+            },
 
-    if ((arch.isARM() or arch.isThumb()) and !is_test) {
-        const __aeabi_unwind_cpp_pr0 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0;
-        @export(__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
-        const __aeabi_unwind_cpp_pr1 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1;
-        @export(__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
-        const __aeabi_unwind_cpp_pr2 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2;
-        @export(__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage });
-
-        @export(__muldi3, .{ .name = "__aeabi_lmul", .linkage = linkage });
-
-        const __aeabi_ldivmod = @import("compiler_rt/arm.zig").__aeabi_ldivmod;
-        @export(__aeabi_ldivmod, .{ .name = "__aeabi_ldivmod", .linkage = linkage });
-        const __aeabi_uldivmod = @import("compiler_rt/arm.zig").__aeabi_uldivmod;
-        @export(__aeabi_uldivmod, .{ .name = "__aeabi_uldivmod", .linkage = linkage });
-
-        @export(__divsi3, .{ .name = "__aeabi_idiv", .linkage = linkage });
-        const __aeabi_idivmod = @import("compiler_rt/arm.zig").__aeabi_idivmod;
-        @export(__aeabi_idivmod, .{ .name = "__aeabi_idivmod", .linkage = linkage });
-        @export(__udivsi3, .{ .name = "__aeabi_uidiv", .linkage = linkage });
-        const __aeabi_uidivmod = @import("compiler_rt/arm.zig").__aeabi_uidivmod;
-        @export(__aeabi_uidivmod, .{ .name = "__aeabi_uidivmod", .linkage = linkage });
-
-        const __aeabi_memcpy = @import("compiler_rt/arm.zig").__aeabi_memcpy;
-        @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy", .linkage = linkage });
-        @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy4", .linkage = linkage });
-        @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy8", .linkage = linkage });
-
-        const __aeabi_memmove = @import("compiler_rt/arm.zig").__aeabi_memmove;
-        @export(__aeabi_memmove, .{ .name = "__aeabi_memmove", .linkage = linkage });
-        @export(__aeabi_memmove, .{ .name = "__aeabi_memmove4", .linkage = linkage });
-        @export(__aeabi_memmove, .{ .name = "__aeabi_memmove8", .linkage = linkage });
-
-        const __aeabi_memset = @import("compiler_rt/arm.zig").__aeabi_memset;
-        @export(__aeabi_memset, .{ .name = "__aeabi_memset", .linkage = linkage });
-        @export(__aeabi_memset, .{ .name = "__aeabi_memset4", .linkage = linkage });
-        @export(__aeabi_memset, .{ .name = "__aeabi_memset8", .linkage = linkage });
-
-        const __aeabi_memclr = @import("compiler_rt/arm.zig").__aeabi_memclr;
-        @export(__aeabi_memclr, .{ .name = "__aeabi_memclr", .linkage = linkage });
-        @export(__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
-        @export(__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
-
-        if (os_tag == .linux) {
-            const __aeabi_read_tp = @import("compiler_rt/arm.zig").__aeabi_read_tp;
-            @export(__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
+            else => {},
         }
 
-        const __aeabi_f2d = @import("compiler_rt/extendXfYf2.zig").__aeabi_f2d;
-        @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage });
-        const __aeabi_i2d = @import("compiler_rt/floatsiXf.zig").__aeabi_i2d;
-        @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage });
-        const __aeabi_l2d = @import("compiler_rt/floatdidf.zig").__aeabi_l2d;
-        @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage });
-        const __aeabi_l2f = @import("compiler_rt/floatXisf.zig").__aeabi_l2f;
-        @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage });
-        const __aeabi_ui2d = @import("compiler_rt/floatunsidf.zig").__aeabi_ui2d;
-        @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage });
-        const __aeabi_ul2d = @import("compiler_rt/floatundidf.zig").__aeabi_ul2d;
-        @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage });
-        const __aeabi_ui2f = @import("compiler_rt/floatunsisf.zig").__aeabi_ui2f;
-        @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage });
-        const __aeabi_ul2f = @import("compiler_rt/floatundisf.zig").__aeabi_ul2f;
-        @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage });
-
-        const __aeabi_fneg = @import("compiler_rt/negXf2.zig").__aeabi_fneg;
-        @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = linkage });
-        const __aeabi_dneg = @import("compiler_rt/negXf2.zig").__aeabi_dneg;
-        @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = linkage });
-
-        const __aeabi_fmul = @import("compiler_rt/mulXf3.zig").__aeabi_fmul;
-        @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = linkage });
-        const __aeabi_dmul = @import("compiler_rt/mulXf3.zig").__aeabi_dmul;
-        @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = linkage });
-
-        const __aeabi_d2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2h;
-        @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage });
-
-        const __aeabi_f2ulz = @import("compiler_rt/fixunssfdi.zig").__aeabi_f2ulz;
-        @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage });
-        const __aeabi_d2ulz = @import("compiler_rt/fixunsdfdi.zig").__aeabi_d2ulz;
-        @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage });
-
-        const __aeabi_f2lz = @import("compiler_rt/fixsfdi.zig").__aeabi_f2lz;
-        @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage });
-        const __aeabi_d2lz = @import("compiler_rt/fixdfdi.zig").__aeabi_d2lz;
-        @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage });
-
-        const __aeabi_d2uiz = @import("compiler_rt/fixunsdfsi.zig").__aeabi_d2uiz;
-        @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage });
-
-        const __aeabi_h2f = @import("compiler_rt/extendXfYf2.zig").__aeabi_h2f;
-        @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = linkage });
-        const __aeabi_f2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_f2h;
-        @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage });
-
-        const __aeabi_i2f = @import("compiler_rt/floatsiXf.zig").__aeabi_i2f;
-        @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage });
-        const __aeabi_d2f = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2f;
-        @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage });
-
-        const __aeabi_fadd = @import("compiler_rt/addXf3.zig").__aeabi_fadd;
-        @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = linkage });
-        const __aeabi_dadd = @import("compiler_rt/addXf3.zig").__aeabi_dadd;
-        @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = linkage });
-        const __aeabi_fsub = @import("compiler_rt/addXf3.zig").__aeabi_fsub;
-        @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = linkage });
-        const __aeabi_dsub = @import("compiler_rt/addXf3.zig").__aeabi_dsub;
-        @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage });
-
-        const __aeabi_f2uiz = @import("compiler_rt/fixunssfsi.zig").__aeabi_f2uiz;
-        @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage });
-
-        const __aeabi_f2iz = @import("compiler_rt/fixsfsi.zig").__aeabi_f2iz;
-        @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage });
-        const __aeabi_d2iz = @import("compiler_rt/fixdfsi.zig").__aeabi_d2iz;
-        @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage });
-
-        const __aeabi_fdiv = @import("compiler_rt/divsf3.zig").__aeabi_fdiv;
-        @export(__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = linkage });
-        const __aeabi_ddiv = @import("compiler_rt/divdf3.zig").__aeabi_ddiv;
-        @export(__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = linkage });
-
-        const __aeabi_llsl = @import("compiler_rt/shift.zig").__aeabi_llsl;
-        @export(__aeabi_llsl, .{ .name = "__aeabi_llsl", .linkage = linkage });
-        const __aeabi_lasr = @import("compiler_rt/shift.zig").__aeabi_lasr;
-        @export(__aeabi_lasr, .{ .name = "__aeabi_lasr", .linkage = linkage });
-        const __aeabi_llsr = @import("compiler_rt/shift.zig").__aeabi_llsr;
-        @export(__aeabi_llsr, .{ .name = "__aeabi_llsr", .linkage = linkage });
-
-        const __aeabi_fcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpeq;
-        @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
-        const __aeabi_fcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmplt;
-        @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
-        const __aeabi_fcmple = @import("compiler_rt/compareXf2.zig").__aeabi_fcmple;
-        @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
-        const __aeabi_fcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpge;
-        @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
-        const __aeabi_fcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpgt;
-        @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
-        const __aeabi_fcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpun;
-        @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
-
-        const __aeabi_dcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpeq;
-        @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
-        const __aeabi_dcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmplt;
-        @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
-        const __aeabi_dcmple = @import("compiler_rt/compareXf2.zig").__aeabi_dcmple;
-        @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
-        const __aeabi_dcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpge;
-        @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
-        const __aeabi_dcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpgt;
-        @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
-        const __aeabi_dcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpun;
-        @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
-    }
+        // __clear_cache manages its own logic about whether to be exported or not.
+        _ = @import("compiler_rt/clear_cache.zig").clear_cache;
+
+        const __lesf2 = @import("compiler_rt/compareXf2.zig").__lesf2;
+        @export(__lesf2, .{ .name = "__lesf2", .linkage = linkage });
+        const __ledf2 = @import("compiler_rt/compareXf2.zig").__ledf2;
+        @export(__ledf2, .{ .name = "__ledf2", .linkage = linkage });
+        const __letf2 = @import("compiler_rt/compareXf2.zig").__letf2;
+        @export(__letf2, .{ .name = "__letf2", .linkage = linkage });
+
+        const __gesf2 = @import("compiler_rt/compareXf2.zig").__gesf2;
+        @export(__gesf2, .{ .name = "__gesf2", .linkage = linkage });
+        const __gedf2 = @import("compiler_rt/compareXf2.zig").__gedf2;
+        @export(__gedf2, .{ .name = "__gedf2", .linkage = linkage });
+        const __getf2 = @import("compiler_rt/compareXf2.zig").__getf2;
+        @export(__getf2, .{ .name = "__getf2", .linkage = linkage });
+
+        if (!is_test) {
+            @export(__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
+            @export(__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__cmptf2", .linkage = linkage });
+
+            const __eqsf2 = @import("compiler_rt/compareXf2.zig").__eqsf2;
+            @export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
+            const __eqdf2 = @import("compiler_rt/compareXf2.zig").__eqdf2;
+            @export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__eqtf2", .linkage = linkage });
+
+            const __ltsf2 = @import("compiler_rt/compareXf2.zig").__ltsf2;
+            @export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
+            const __ltdf2 = @import("compiler_rt/compareXf2.zig").__ltdf2;
+            @export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__lttf2", .linkage = linkage });
+
+            const __nesf2 = @import("compiler_rt/compareXf2.zig").__nesf2;
+            @export(__nesf2, .{ .name = "__nesf2", .linkage = linkage });
+            const __nedf2 = @import("compiler_rt/compareXf2.zig").__nedf2;
+            @export(__nedf2, .{ .name = "__nedf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__netf2", .linkage = linkage });
+
+            const __gtsf2 = @import("compiler_rt/compareXf2.zig").__gtsf2;
+            @export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
+            const __gtdf2 = @import("compiler_rt/compareXf2.zig").__gtdf2;
+            @export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
+            @export(__getf2, .{ .name = "__gttf2", .linkage = linkage });
+
+            @export(@import("compiler_rt/extendXfYf2.zig").__extendhfsf2, .{
+                .name = "__gnu_h2f_ieee",
+                .linkage = linkage,
+            });
+            @export(@import("compiler_rt/truncXfYf2.zig").__truncsfhf2, .{
+                .name = "__gnu_f2h_ieee",
+                .linkage = linkage,
+            });
+        }
 
-    if (arch == .i386 and abi == .msvc) {
-        // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
-        const _alldiv = @import("compiler_rt/aulldiv.zig")._alldiv;
-        @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
-        const _aulldiv = @import("compiler_rt/aulldiv.zig")._aulldiv;
-        @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
-        const _allrem = @import("compiler_rt/aullrem.zig")._allrem;
-        @export(_allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
-        const _aullrem = @import("compiler_rt/aullrem.zig")._aullrem;
-        @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
-    }
+        const __unordsf2 = @import("compiler_rt/compareXf2.zig").__unordsf2;
+        @export(__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
+        const __unorddf2 = @import("compiler_rt/compareXf2.zig").__unorddf2;
+        @export(__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
+        const __unordtf2 = @import("compiler_rt/compareXf2.zig").__unordtf2;
+        @export(__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
+
+        const __addsf3 = @import("compiler_rt/addXf3.zig").__addsf3;
+        @export(__addsf3, .{ .name = "__addsf3", .linkage = linkage });
+        const __adddf3 = @import("compiler_rt/addXf3.zig").__adddf3;
+        @export(__adddf3, .{ .name = "__adddf3", .linkage = linkage });
+        const __addtf3 = @import("compiler_rt/addXf3.zig").__addtf3;
+        @export(__addtf3, .{ .name = "__addtf3", .linkage = linkage });
+        const __subsf3 = @import("compiler_rt/addXf3.zig").__subsf3;
+        @export(__subsf3, .{ .name = "__subsf3", .linkage = linkage });
+        const __subdf3 = @import("compiler_rt/addXf3.zig").__subdf3;
+        @export(__subdf3, .{ .name = "__subdf3", .linkage = linkage });
+        const __subtf3 = @import("compiler_rt/addXf3.zig").__subtf3;
+        @export(__subtf3, .{ .name = "__subtf3", .linkage = linkage });
+
+        const __mulsf3 = @import("compiler_rt/mulXf3.zig").__mulsf3;
+        @export(__mulsf3, .{ .name = "__mulsf3", .linkage = linkage });
+        const __muldf3 = @import("compiler_rt/mulXf3.zig").__muldf3;
+        @export(__muldf3, .{ .name = "__muldf3", .linkage = linkage });
+        const __multf3 = @import("compiler_rt/mulXf3.zig").__multf3;
+        @export(__multf3, .{ .name = "__multf3", .linkage = linkage });
+
+        const __divsf3 = @import("compiler_rt/divsf3.zig").__divsf3;
+        @export(__divsf3, .{ .name = "__divsf3", .linkage = linkage });
+        const __divdf3 = @import("compiler_rt/divdf3.zig").__divdf3;
+        @export(__divdf3, .{ .name = "__divdf3", .linkage = linkage });
+        const __divtf3 = @import("compiler_rt/divtf3.zig").__divtf3;
+        @export(__divtf3, .{ .name = "__divtf3", .linkage = linkage });
+
+        const __ashldi3 = @import("compiler_rt/shift.zig").__ashldi3;
+        @export(__ashldi3, .{ .name = "__ashldi3", .linkage = linkage });
+        const __ashlti3 = @import("compiler_rt/shift.zig").__ashlti3;
+        @export(__ashlti3, .{ .name = "__ashlti3", .linkage = linkage });
+        const __ashrdi3 = @import("compiler_rt/shift.zig").__ashrdi3;
+        @export(__ashrdi3, .{ .name = "__ashrdi3", .linkage = linkage });
+        const __ashrti3 = @import("compiler_rt/shift.zig").__ashrti3;
+        @export(__ashrti3, .{ .name = "__ashrti3", .linkage = linkage });
+        const __lshrdi3 = @import("compiler_rt/shift.zig").__lshrdi3;
+        @export(__lshrdi3, .{ .name = "__lshrdi3", .linkage = linkage });
+        const __lshrti3 = @import("compiler_rt/shift.zig").__lshrti3;
+        @export(__lshrti3, .{ .name = "__lshrti3", .linkage = linkage });
+
+        const __floatsidf = @import("compiler_rt/floatsiXf.zig").__floatsidf;
+        @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage });
+        const __floatsisf = @import("compiler_rt/floatsiXf.zig").__floatsisf;
+        @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage });
+        const __floatdidf = @import("compiler_rt/floatdidf.zig").__floatdidf;
+        @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage });
+        const __floatsitf = @import("compiler_rt/floatsiXf.zig").__floatsitf;
+        @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage });
+
+        const __floatunsisf = @import("compiler_rt/floatunsisf.zig").__floatunsisf;
+        @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage });
+        const __floatundisf = @import("compiler_rt/floatundisf.zig").__floatundisf;
+        @export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage });
+        const __floatunsidf = @import("compiler_rt/floatunsidf.zig").__floatunsidf;
+        @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage });
+        const __floatundidf = @import("compiler_rt/floatundidf.zig").__floatundidf;
+        @export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage });
+
+        const __floatditf = @import("compiler_rt/floatditf.zig").__floatditf;
+        @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage });
+        const __floattitf = @import("compiler_rt/floattitf.zig").__floattitf;
+        @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage });
+        const __floattidf = @import("compiler_rt/floattidf.zig").__floattidf;
+        @export(__floattidf, .{ .name = "__floattidf", .linkage = linkage });
+        const __floattisf = @import("compiler_rt/floatXisf.zig").__floattisf;
+        @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage });
+        const __floatdisf = @import("compiler_rt/floatXisf.zig").__floatdisf;
+        @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage });
+
+        const __floatunditf = @import("compiler_rt/floatunditf.zig").__floatunditf;
+        @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage });
+        const __floatunsitf = @import("compiler_rt/floatunsitf.zig").__floatunsitf;
+        @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage });
+
+        const __floatuntitf = @import("compiler_rt/floatuntitf.zig").__floatuntitf;
+        @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage });
+        const __floatuntidf = @import("compiler_rt/floatuntidf.zig").__floatuntidf;
+        @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage });
+        const __floatuntisf = @import("compiler_rt/floatuntisf.zig").__floatuntisf;
+        @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage });
 
-    if (arch.isSPARC()) {
-        // SPARC systems use a different naming scheme
-        const _Qp_add = @import("compiler_rt/sparc.zig")._Qp_add;
-        @export(_Qp_add, .{ .name = "_Qp_add", .linkage = linkage });
-        const _Qp_div = @import("compiler_rt/sparc.zig")._Qp_div;
-        @export(_Qp_div, .{ .name = "_Qp_div", .linkage = linkage });
-        const _Qp_mul = @import("compiler_rt/sparc.zig")._Qp_mul;
-        @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = linkage });
-        const _Qp_sub = @import("compiler_rt/sparc.zig")._Qp_sub;
-        @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = linkage });
-
-        const _Qp_cmp = @import("compiler_rt/sparc.zig")._Qp_cmp;
-        @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = linkage });
-        const _Qp_feq = @import("compiler_rt/sparc.zig")._Qp_feq;
-        @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = linkage });
-        const _Qp_fne = @import("compiler_rt/sparc.zig")._Qp_fne;
-        @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = linkage });
-        const _Qp_flt = @import("compiler_rt/sparc.zig")._Qp_flt;
-        @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = linkage });
-        const _Qp_fle = @import("compiler_rt/sparc.zig")._Qp_fle;
-        @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = linkage });
-        const _Qp_fgt = @import("compiler_rt/sparc.zig")._Qp_fgt;
-        @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = linkage });
-        const _Qp_fge = @import("compiler_rt/sparc.zig")._Qp_fge;
-        @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = linkage });
-
-        const _Qp_itoq = @import("compiler_rt/sparc.zig")._Qp_itoq;
-        @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = linkage });
-        const _Qp_uitoq = @import("compiler_rt/sparc.zig")._Qp_uitoq;
-        @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = linkage });
-        const _Qp_xtoq = @import("compiler_rt/sparc.zig")._Qp_xtoq;
-        @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = linkage });
-        const _Qp_uxtoq = @import("compiler_rt/sparc.zig")._Qp_uxtoq;
-        @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = linkage });
-        const _Qp_stoq = @import("compiler_rt/sparc.zig")._Qp_stoq;
-        @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = linkage });
-        const _Qp_dtoq = @import("compiler_rt/sparc.zig")._Qp_dtoq;
-        @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = linkage });
-        const _Qp_qtoi = @import("compiler_rt/sparc.zig")._Qp_qtoi;
-        @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = linkage });
-        const _Qp_qtoui = @import("compiler_rt/sparc.zig")._Qp_qtoui;
-        @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = linkage });
-        const _Qp_qtox = @import("compiler_rt/sparc.zig")._Qp_qtox;
-        @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = linkage });
-        const _Qp_qtoux = @import("compiler_rt/sparc.zig")._Qp_qtoux;
-        @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = linkage });
-        const _Qp_qtos = @import("compiler_rt/sparc.zig")._Qp_qtos;
-        @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = linkage });
-        const _Qp_qtod = @import("compiler_rt/sparc.zig")._Qp_qtod;
-        @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage });
-    }
+        const __truncsfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncsfhf2;
+        @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage });
+        const __truncdfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfhf2;
+        @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage });
+        const __trunctfhf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfhf2;
+        @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage });
+        const __trunctfdf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfdf2;
+        @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage });
+        const __trunctfsf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfsf2;
+        @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage });
+
+        const __truncdfsf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfsf2;
+        @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage });
+
+        const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2;
+        @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage });
+
+        const __fixunssfsi = @import("compiler_rt/fixunssfsi.zig").__fixunssfsi;
+        @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage });
+        const __fixunssfdi = @import("compiler_rt/fixunssfdi.zig").__fixunssfdi;
+        @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage });
+        const __fixunssfti = @import("compiler_rt/fixunssfti.zig").__fixunssfti;
+        @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage });
+
+        const __fixunsdfsi = @import("compiler_rt/fixunsdfsi.zig").__fixunsdfsi;
+        @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage });
+        const __fixunsdfdi = @import("compiler_rt/fixunsdfdi.zig").__fixunsdfdi;
+        @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage });
+        const __fixunsdfti = @import("compiler_rt/fixunsdfti.zig").__fixunsdfti;
+        @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage });
+
+        const __fixunstfsi = @import("compiler_rt/fixunstfsi.zig").__fixunstfsi;
+        @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage });
+        const __fixunstfdi = @import("compiler_rt/fixunstfdi.zig").__fixunstfdi;
+        @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage });
+        const __fixunstfti = @import("compiler_rt/fixunstfti.zig").__fixunstfti;
+        @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage });
+
+        const __fixdfdi = @import("compiler_rt/fixdfdi.zig").__fixdfdi;
+        @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage });
+        const __fixdfsi = @import("compiler_rt/fixdfsi.zig").__fixdfsi;
+        @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage });
+        const __fixdfti = @import("compiler_rt/fixdfti.zig").__fixdfti;
+        @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage });
+        const __fixsfdi = @import("compiler_rt/fixsfdi.zig").__fixsfdi;
+        @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage });
+        const __fixsfsi = @import("compiler_rt/fixsfsi.zig").__fixsfsi;
+        @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage });
+        const __fixsfti = @import("compiler_rt/fixsfti.zig").__fixsfti;
+        @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage });
+        const __fixtfdi = @import("compiler_rt/fixtfdi.zig").__fixtfdi;
+        @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage });
+        const __fixtfsi = @import("compiler_rt/fixtfsi.zig").__fixtfsi;
+        @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage });
+        const __fixtfti = @import("compiler_rt/fixtfti.zig").__fixtfti;
+        @export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage });
+
+        const __udivmoddi4 = @import("compiler_rt/int.zig").__udivmoddi4;
+        @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = linkage });
+        const __popcountdi2 = @import("compiler_rt/popcountdi2.zig").__popcountdi2;
+        @export(__popcountdi2, .{ .name = "__popcountdi2", .linkage = linkage });
+
+        const __mulsi3 = @import("compiler_rt/int.zig").__mulsi3;
+        @export(__mulsi3, .{ .name = "__mulsi3", .linkage = linkage });
+        const __muldi3 = @import("compiler_rt/muldi3.zig").__muldi3;
+        @export(__muldi3, .{ .name = "__muldi3", .linkage = linkage });
+        const __divmoddi4 = @import("compiler_rt/int.zig").__divmoddi4;
+        @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = linkage });
+        const __divsi3 = @import("compiler_rt/int.zig").__divsi3;
+        @export(__divsi3, .{ .name = "__divsi3", .linkage = linkage });
+        const __divdi3 = @import("compiler_rt/int.zig").__divdi3;
+        @export(__divdi3, .{ .name = "__divdi3", .linkage = linkage });
+        const __udivsi3 = @import("compiler_rt/int.zig").__udivsi3;
+        @export(__udivsi3, .{ .name = "__udivsi3", .linkage = linkage });
+        const __udivdi3 = @import("compiler_rt/int.zig").__udivdi3;
+        @export(__udivdi3, .{ .name = "__udivdi3", .linkage = linkage });
+        const __modsi3 = @import("compiler_rt/int.zig").__modsi3;
+        @export(__modsi3, .{ .name = "__modsi3", .linkage = linkage });
+        const __moddi3 = @import("compiler_rt/int.zig").__moddi3;
+        @export(__moddi3, .{ .name = "__moddi3", .linkage = linkage });
+        const __umodsi3 = @import("compiler_rt/int.zig").__umodsi3;
+        @export(__umodsi3, .{ .name = "__umodsi3", .linkage = linkage });
+        const __umoddi3 = @import("compiler_rt/int.zig").__umoddi3;
+        @export(__umoddi3, .{ .name = "__umoddi3", .linkage = linkage });
+        const __divmodsi4 = @import("compiler_rt/int.zig").__divmodsi4;
+        @export(__divmodsi4, .{ .name = "__divmodsi4", .linkage = linkage });
+        const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4;
+        @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage });
+
+        const __negsf2 = @import("compiler_rt/negXf2.zig").__negsf2;
+        @export(__negsf2, .{ .name = "__negsf2", .linkage = linkage });
+        const __negdf2 = @import("compiler_rt/negXf2.zig").__negdf2;
+        @export(__negdf2, .{ .name = "__negdf2", .linkage = linkage });
+
+        const __clzsi2 = @import("compiler_rt/count0bits.zig").__clzsi2;
+        @export(__clzsi2, .{ .name = "__clzsi2", .linkage = linkage });
+        const __clzdi2 = @import("compiler_rt/count0bits.zig").__clzdi2;
+        @export(__clzdi2, .{ .name = "__clzdi2", .linkage = linkage });
+        const __clzti2 = @import("compiler_rt/count0bits.zig").__clzti2;
+        @export(__clzti2, .{ .name = "__clzti2", .linkage = linkage });
+
+        if (builtin.link_libc and os_tag == .openbsd) {
+            const __emutls_get_address = @import("compiler_rt/emutls.zig").__emutls_get_address;
+            @export(__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = linkage });
+        }
 
-    if ((arch == .powerpc or arch.isPPC64()) and !is_test) {
-        @export(__addtf3, .{ .name = "__addkf3", .linkage = linkage });
-        @export(__subtf3, .{ .name = "__subkf3", .linkage = linkage });
-        @export(__multf3, .{ .name = "__mulkf3", .linkage = linkage });
-        @export(__divtf3, .{ .name = "__divkf3", .linkage = linkage });
-        @export(__extendsftf2, .{ .name = "__extendsfkf2", .linkage = linkage });
-        @export(__extenddftf2, .{ .name = "__extenddfkf2", .linkage = linkage });
-        @export(__trunctfsf2, .{ .name = "__trunckfsf2", .linkage = linkage });
-        @export(__trunctfdf2, .{ .name = "__trunckfdf2", .linkage = linkage });
-        @export(__fixtfdi, .{ .name = "__fixkfdi", .linkage = linkage });
-        @export(__fixtfsi, .{ .name = "__fixkfsi", .linkage = linkage });
-        @export(__fixunstfsi, .{ .name = "__fixunskfsi", .linkage = linkage });
-        @export(__fixunstfdi, .{ .name = "__fixunskfdi", .linkage = linkage });
-        @export(__floatsitf, .{ .name = "__floatsikf", .linkage = linkage });
-        @export(__floatditf, .{ .name = "__floatdikf", .linkage = linkage });
-        @export(__floatunditf, .{ .name = "__floatundikf", .linkage = linkage });
-        @export(__floatunsitf, .{ .name = "__floatunsikf", .linkage = linkage });
-
-        @export(__letf2, .{ .name = "__eqkf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__nekf2", .linkage = linkage });
-        @export(__getf2, .{ .name = "__gekf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__ltkf2", .linkage = linkage });
-        @export(__letf2, .{ .name = "__lekf2", .linkage = linkage });
-        @export(__getf2, .{ .name = "__gtkf2", .linkage = linkage });
-        @export(__unordtf2, .{ .name = "__unordkf2", .linkage = linkage });
-    }
+        if ((arch.isARM() or arch.isThumb()) and !is_test) {
+            const __aeabi_unwind_cpp_pr0 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0;
+            @export(__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
+            const __aeabi_unwind_cpp_pr1 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1;
+            @export(__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
+            const __aeabi_unwind_cpp_pr2 = @import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2;
+            @export(__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage });
+
+            @export(__muldi3, .{ .name = "__aeabi_lmul", .linkage = linkage });
+
+            const __aeabi_ldivmod = @import("compiler_rt/arm.zig").__aeabi_ldivmod;
+            @export(__aeabi_ldivmod, .{ .name = "__aeabi_ldivmod", .linkage = linkage });
+            const __aeabi_uldivmod = @import("compiler_rt/arm.zig").__aeabi_uldivmod;
+            @export(__aeabi_uldivmod, .{ .name = "__aeabi_uldivmod", .linkage = linkage });
+
+            @export(__divsi3, .{ .name = "__aeabi_idiv", .linkage = linkage });
+            const __aeabi_idivmod = @import("compiler_rt/arm.zig").__aeabi_idivmod;
+            @export(__aeabi_idivmod, .{ .name = "__aeabi_idivmod", .linkage = linkage });
+            @export(__udivsi3, .{ .name = "__aeabi_uidiv", .linkage = linkage });
+            const __aeabi_uidivmod = @import("compiler_rt/arm.zig").__aeabi_uidivmod;
+            @export(__aeabi_uidivmod, .{ .name = "__aeabi_uidivmod", .linkage = linkage });
+
+            const __aeabi_memcpy = @import("compiler_rt/arm.zig").__aeabi_memcpy;
+            @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy", .linkage = linkage });
+            @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy4", .linkage = linkage });
+            @export(__aeabi_memcpy, .{ .name = "__aeabi_memcpy8", .linkage = linkage });
+
+            const __aeabi_memmove = @import("compiler_rt/arm.zig").__aeabi_memmove;
+            @export(__aeabi_memmove, .{ .name = "__aeabi_memmove", .linkage = linkage });
+            @export(__aeabi_memmove, .{ .name = "__aeabi_memmove4", .linkage = linkage });
+            @export(__aeabi_memmove, .{ .name = "__aeabi_memmove8", .linkage = linkage });
+
+            const __aeabi_memset = @import("compiler_rt/arm.zig").__aeabi_memset;
+            @export(__aeabi_memset, .{ .name = "__aeabi_memset", .linkage = linkage });
+            @export(__aeabi_memset, .{ .name = "__aeabi_memset4", .linkage = linkage });
+            @export(__aeabi_memset, .{ .name = "__aeabi_memset8", .linkage = linkage });
+
+            const __aeabi_memclr = @import("compiler_rt/arm.zig").__aeabi_memclr;
+            @export(__aeabi_memclr, .{ .name = "__aeabi_memclr", .linkage = linkage });
+            @export(__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
+            @export(__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
+
+            if (os_tag == .linux) {
+                const __aeabi_read_tp = @import("compiler_rt/arm.zig").__aeabi_read_tp;
+                @export(__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
+            }
+
+            const __aeabi_f2d = @import("compiler_rt/extendXfYf2.zig").__aeabi_f2d;
+            @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage });
+            const __aeabi_i2d = @import("compiler_rt/floatsiXf.zig").__aeabi_i2d;
+            @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage });
+            const __aeabi_l2d = @import("compiler_rt/floatdidf.zig").__aeabi_l2d;
+            @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage });
+            const __aeabi_l2f = @import("compiler_rt/floatXisf.zig").__aeabi_l2f;
+            @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage });
+            const __aeabi_ui2d = @import("compiler_rt/floatunsidf.zig").__aeabi_ui2d;
+            @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage });
+            const __aeabi_ul2d = @import("compiler_rt/floatundidf.zig").__aeabi_ul2d;
+            @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage });
+            const __aeabi_ui2f = @import("compiler_rt/floatunsisf.zig").__aeabi_ui2f;
+            @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage });
+            const __aeabi_ul2f = @import("compiler_rt/floatundisf.zig").__aeabi_ul2f;
+            @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage });
+
+            const __aeabi_fneg = @import("compiler_rt/negXf2.zig").__aeabi_fneg;
+            @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = linkage });
+            const __aeabi_dneg = @import("compiler_rt/negXf2.zig").__aeabi_dneg;
+            @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = linkage });
+
+            const __aeabi_fmul = @import("compiler_rt/mulXf3.zig").__aeabi_fmul;
+            @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = linkage });
+            const __aeabi_dmul = @import("compiler_rt/mulXf3.zig").__aeabi_dmul;
+            @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = linkage });
+
+            const __aeabi_d2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2h;
+            @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage });
+
+            const __aeabi_f2ulz = @import("compiler_rt/fixunssfdi.zig").__aeabi_f2ulz;
+            @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage });
+            const __aeabi_d2ulz = @import("compiler_rt/fixunsdfdi.zig").__aeabi_d2ulz;
+            @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage });
+
+            const __aeabi_f2lz = @import("compiler_rt/fixsfdi.zig").__aeabi_f2lz;
+            @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage });
+            const __aeabi_d2lz = @import("compiler_rt/fixdfdi.zig").__aeabi_d2lz;
+            @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage });
+
+            const __aeabi_d2uiz = @import("compiler_rt/fixunsdfsi.zig").__aeabi_d2uiz;
+            @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage });
+
+            const __aeabi_h2f = @import("compiler_rt/extendXfYf2.zig").__aeabi_h2f;
+            @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = linkage });
+            const __aeabi_f2h = @import("compiler_rt/truncXfYf2.zig").__aeabi_f2h;
+            @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage });
+
+            const __aeabi_i2f = @import("compiler_rt/floatsiXf.zig").__aeabi_i2f;
+            @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage });
+            const __aeabi_d2f = @import("compiler_rt/truncXfYf2.zig").__aeabi_d2f;
+            @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage });
+
+            const __aeabi_fadd = @import("compiler_rt/addXf3.zig").__aeabi_fadd;
+            @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = linkage });
+            const __aeabi_dadd = @import("compiler_rt/addXf3.zig").__aeabi_dadd;
+            @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = linkage });
+            const __aeabi_fsub = @import("compiler_rt/addXf3.zig").__aeabi_fsub;
+            @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = linkage });
+            const __aeabi_dsub = @import("compiler_rt/addXf3.zig").__aeabi_dsub;
+            @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage });
+
+            const __aeabi_f2uiz = @import("compiler_rt/fixunssfsi.zig").__aeabi_f2uiz;
+            @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage });
+
+            const __aeabi_f2iz = @import("compiler_rt/fixsfsi.zig").__aeabi_f2iz;
+            @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage });
+            const __aeabi_d2iz = @import("compiler_rt/fixdfsi.zig").__aeabi_d2iz;
+            @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage });
+
+            const __aeabi_fdiv = @import("compiler_rt/divsf3.zig").__aeabi_fdiv;
+            @export(__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = linkage });
+            const __aeabi_ddiv = @import("compiler_rt/divdf3.zig").__aeabi_ddiv;
+            @export(__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = linkage });
+
+            const __aeabi_llsl = @import("compiler_rt/shift.zig").__aeabi_llsl;
+            @export(__aeabi_llsl, .{ .name = "__aeabi_llsl", .linkage = linkage });
+            const __aeabi_lasr = @import("compiler_rt/shift.zig").__aeabi_lasr;
+            @export(__aeabi_lasr, .{ .name = "__aeabi_lasr", .linkage = linkage });
+            const __aeabi_llsr = @import("compiler_rt/shift.zig").__aeabi_llsr;
+            @export(__aeabi_llsr, .{ .name = "__aeabi_llsr", .linkage = linkage });
+
+            const __aeabi_fcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpeq;
+            @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
+            const __aeabi_fcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmplt;
+            @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
+            const __aeabi_fcmple = @import("compiler_rt/compareXf2.zig").__aeabi_fcmple;
+            @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
+            const __aeabi_fcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpge;
+            @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
+            const __aeabi_fcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpgt;
+            @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
+            const __aeabi_fcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_fcmpun;
+            @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
+
+            const __aeabi_dcmpeq = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpeq;
+            @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
+            const __aeabi_dcmplt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmplt;
+            @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
+            const __aeabi_dcmple = @import("compiler_rt/compareXf2.zig").__aeabi_dcmple;
+            @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
+            const __aeabi_dcmpge = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpge;
+            @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
+            const __aeabi_dcmpgt = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpgt;
+            @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
+            const __aeabi_dcmpun = @import("compiler_rt/compareXf2.zig").__aeabi_dcmpun;
+            @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
+        }
 
-    if (builtin.os.tag == .windows) {
-        // Default stack-probe functions emitted by LLVM
-        if (is_mingw) {
-            const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk;
-            @export(_chkstk, .{ .name = "_alloca", .linkage = strong_linkage });
-            const ___chkstk_ms = @import("compiler_rt/stack_probe.zig").___chkstk_ms;
-            @export(___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = strong_linkage });
-        } else if (!builtin.link_libc) {
-            // This symbols are otherwise exported by MSVCRT.lib
-            const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk;
-            @export(_chkstk, .{ .name = "_chkstk", .linkage = strong_linkage });
-            const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk;
-            @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
+        if (arch == .i386 and abi == .msvc) {
+            // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
+            const _alldiv = @import("compiler_rt/aulldiv.zig")._alldiv;
+            @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
+            const _aulldiv = @import("compiler_rt/aulldiv.zig")._aulldiv;
+            @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
+            const _allrem = @import("compiler_rt/aullrem.zig")._allrem;
+            @export(_allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
+            const _aullrem = @import("compiler_rt/aullrem.zig")._aullrem;
+            @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
         }
 
-        switch (arch) {
-            .i386 => {
-                const __divti3 = @import("compiler_rt/divti3.zig").__divti3;
-                @export(__divti3, .{ .name = "__divti3", .linkage = linkage });
+        if (arch.isSPARC()) {
+            // SPARC systems use a different naming scheme
+            const _Qp_add = @import("compiler_rt/sparc.zig")._Qp_add;
+            @export(_Qp_add, .{ .name = "_Qp_add", .linkage = linkage });
+            const _Qp_div = @import("compiler_rt/sparc.zig")._Qp_div;
+            @export(_Qp_div, .{ .name = "_Qp_div", .linkage = linkage });
+            const _Qp_mul = @import("compiler_rt/sparc.zig")._Qp_mul;
+            @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = linkage });
+            const _Qp_sub = @import("compiler_rt/sparc.zig")._Qp_sub;
+            @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = linkage });
+
+            const _Qp_cmp = @import("compiler_rt/sparc.zig")._Qp_cmp;
+            @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = linkage });
+            const _Qp_feq = @import("compiler_rt/sparc.zig")._Qp_feq;
+            @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = linkage });
+            const _Qp_fne = @import("compiler_rt/sparc.zig")._Qp_fne;
+            @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = linkage });
+            const _Qp_flt = @import("compiler_rt/sparc.zig")._Qp_flt;
+            @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = linkage });
+            const _Qp_fle = @import("compiler_rt/sparc.zig")._Qp_fle;
+            @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = linkage });
+            const _Qp_fgt = @import("compiler_rt/sparc.zig")._Qp_fgt;
+            @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = linkage });
+            const _Qp_fge = @import("compiler_rt/sparc.zig")._Qp_fge;
+            @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = linkage });
+
+            const _Qp_itoq = @import("compiler_rt/sparc.zig")._Qp_itoq;
+            @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = linkage });
+            const _Qp_uitoq = @import("compiler_rt/sparc.zig")._Qp_uitoq;
+            @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = linkage });
+            const _Qp_xtoq = @import("compiler_rt/sparc.zig")._Qp_xtoq;
+            @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = linkage });
+            const _Qp_uxtoq = @import("compiler_rt/sparc.zig")._Qp_uxtoq;
+            @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = linkage });
+            const _Qp_stoq = @import("compiler_rt/sparc.zig")._Qp_stoq;
+            @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = linkage });
+            const _Qp_dtoq = @import("compiler_rt/sparc.zig")._Qp_dtoq;
+            @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = linkage });
+            const _Qp_qtoi = @import("compiler_rt/sparc.zig")._Qp_qtoi;
+            @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = linkage });
+            const _Qp_qtoui = @import("compiler_rt/sparc.zig")._Qp_qtoui;
+            @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = linkage });
+            const _Qp_qtox = @import("compiler_rt/sparc.zig")._Qp_qtox;
+            @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = linkage });
+            const _Qp_qtoux = @import("compiler_rt/sparc.zig")._Qp_qtoux;
+            @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = linkage });
+            const _Qp_qtos = @import("compiler_rt/sparc.zig")._Qp_qtos;
+            @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = linkage });
+            const _Qp_qtod = @import("compiler_rt/sparc.zig")._Qp_qtod;
+            @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage });
+        }
+
+        if ((arch == .powerpc or arch.isPPC64()) and !is_test) {
+            @export(__addtf3, .{ .name = "__addkf3", .linkage = linkage });
+            @export(__subtf3, .{ .name = "__subkf3", .linkage = linkage });
+            @export(__multf3, .{ .name = "__mulkf3", .linkage = linkage });
+            @export(__divtf3, .{ .name = "__divkf3", .linkage = linkage });
+            @export(__extendsftf2, .{ .name = "__extendsfkf2", .linkage = linkage });
+            @export(__extenddftf2, .{ .name = "__extenddfkf2", .linkage = linkage });
+            @export(__trunctfsf2, .{ .name = "__trunckfsf2", .linkage = linkage });
+            @export(__trunctfdf2, .{ .name = "__trunckfdf2", .linkage = linkage });
+            @export(__fixtfdi, .{ .name = "__fixkfdi", .linkage = linkage });
+            @export(__fixtfsi, .{ .name = "__fixkfsi", .linkage = linkage });
+            @export(__fixunstfsi, .{ .name = "__fixunskfsi", .linkage = linkage });
+            @export(__fixunstfdi, .{ .name = "__fixunskfdi", .linkage = linkage });
+            @export(__floatsitf, .{ .name = "__floatsikf", .linkage = linkage });
+            @export(__floatditf, .{ .name = "__floatdikf", .linkage = linkage });
+            @export(__floatunditf, .{ .name = "__floatundikf", .linkage = linkage });
+            @export(__floatunsitf, .{ .name = "__floatunsikf", .linkage = linkage });
+
+            @export(__letf2, .{ .name = "__eqkf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__nekf2", .linkage = linkage });
+            @export(__getf2, .{ .name = "__gekf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__ltkf2", .linkage = linkage });
+            @export(__letf2, .{ .name = "__lekf2", .linkage = linkage });
+            @export(__getf2, .{ .name = "__gtkf2", .linkage = linkage });
+            @export(__unordtf2, .{ .name = "__unordkf2", .linkage = linkage });
+        }
+
+        if (builtin.os.tag == .windows) {
+            // Default stack-probe functions emitted by LLVM
+            if (is_mingw) {
+                const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk;
+                @export(_chkstk, .{ .name = "_alloca", .linkage = strong_linkage });
+                const ___chkstk_ms = @import("compiler_rt/stack_probe.zig").___chkstk_ms;
+                @export(___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = strong_linkage });
+            } else if (!builtin.link_libc) {
+                // This symbols are otherwise exported by MSVCRT.lib
+                const _chkstk = @import("compiler_rt/stack_probe.zig")._chkstk;
+                @export(_chkstk, .{ .name = "_chkstk", .linkage = strong_linkage });
+                const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk;
+                @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
+            }
+
+            switch (arch) {
+                .i386 => {
+                    const __divti3 = @import("compiler_rt/divti3.zig").__divti3;
+                    @export(__divti3, .{ .name = "__divti3", .linkage = linkage });
+                    const __modti3 = @import("compiler_rt/modti3.zig").__modti3;
+                    @export(__modti3, .{ .name = "__modti3", .linkage = linkage });
+                    const __multi3 = @import("compiler_rt/multi3.zig").__multi3;
+                    @export(__multi3, .{ .name = "__multi3", .linkage = linkage });
+                    const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3;
+                    @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage });
+                    const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4;
+                    @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage });
+                    const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3;
+                    @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
+                },
+                .x86_64 => {
+                    // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI
+                    // that LLVM expects compiler-rt to have.
+                    const __divti3_windows_x86_64 = @import("compiler_rt/divti3.zig").__divti3_windows_x86_64;
+                    @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = linkage });
+                    const __modti3_windows_x86_64 = @import("compiler_rt/modti3.zig").__modti3_windows_x86_64;
+                    @export(__modti3_windows_x86_64, .{ .name = "__modti3", .linkage = linkage });
+                    const __multi3_windows_x86_64 = @import("compiler_rt/multi3.zig").__multi3_windows_x86_64;
+                    @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = linkage });
+                    const __udivti3_windows_x86_64 = @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64;
+                    @export(__udivti3_windows_x86_64, .{ .name = "__udivti3", .linkage = linkage });
+                    const __udivmodti4_windows_x86_64 = @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64;
+                    @export(__udivmodti4_windows_x86_64, .{ .name = "__udivmodti4", .linkage = linkage });
+                    const __umodti3_windows_x86_64 = @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64;
+                    @export(__umodti3_windows_x86_64, .{ .name = "__umodti3", .linkage = linkage });
+                },
+                else => {},
+            }
+            if (arch.isAARCH64()) {
+                const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk;
+                @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
+                const __divti3_windows = @import("compiler_rt/divti3.zig").__divti3;
+                @export(__divti3_windows, .{ .name = "__divti3", .linkage = linkage });
                 const __modti3 = @import("compiler_rt/modti3.zig").__modti3;
                 @export(__modti3, .{ .name = "__modti3", .linkage = linkage });
-                const __multi3 = @import("compiler_rt/multi3.zig").__multi3;
-                @export(__multi3, .{ .name = "__multi3", .linkage = linkage });
-                const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3;
-                @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage });
-                const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4;
-                @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage });
+                const __udivti3_windows = @import("compiler_rt/udivti3.zig").__udivti3;
+                @export(__udivti3_windows, .{ .name = "__udivti3", .linkage = linkage });
                 const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3;
                 @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
-            },
-            .x86_64 => {
-                // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI
-                // that LLVM expects compiler-rt to have.
-                const __divti3_windows_x86_64 = @import("compiler_rt/divti3.zig").__divti3_windows_x86_64;
-                @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = linkage });
-                const __modti3_windows_x86_64 = @import("compiler_rt/modti3.zig").__modti3_windows_x86_64;
-                @export(__modti3_windows_x86_64, .{ .name = "__modti3", .linkage = linkage });
-                const __multi3_windows_x86_64 = @import("compiler_rt/multi3.zig").__multi3_windows_x86_64;
-                @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = linkage });
-                const __udivti3_windows_x86_64 = @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64;
-                @export(__udivti3_windows_x86_64, .{ .name = "__udivti3", .linkage = linkage });
-                const __udivmodti4_windows_x86_64 = @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64;
-                @export(__udivmodti4_windows_x86_64, .{ .name = "__udivmodti4", .linkage = linkage });
-                const __umodti3_windows_x86_64 = @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64;
-                @export(__umodti3_windows_x86_64, .{ .name = "__umodti3", .linkage = linkage });
-            },
-            else => {},
-        }
-        if (arch.isAARCH64()) {
-            const __chkstk = @import("compiler_rt/stack_probe.zig").__chkstk;
-            @export(__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
-            const __divti3_windows = @import("compiler_rt/divti3.zig").__divti3;
-            @export(__divti3_windows, .{ .name = "__divti3", .linkage = linkage });
+            }
+        } else {
+            const __divti3 = @import("compiler_rt/divti3.zig").__divti3;
+            @export(__divti3, .{ .name = "__divti3", .linkage = linkage });
             const __modti3 = @import("compiler_rt/modti3.zig").__modti3;
             @export(__modti3, .{ .name = "__modti3", .linkage = linkage });
-            const __udivti3_windows = @import("compiler_rt/udivti3.zig").__udivti3;
-            @export(__udivti3_windows, .{ .name = "__udivti3", .linkage = linkage });
+            const __multi3 = @import("compiler_rt/multi3.zig").__multi3;
+            @export(__multi3, .{ .name = "__multi3", .linkage = linkage });
+            const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3;
+            @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage });
+            const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4;
+            @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage });
             const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3;
             @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
         }
-    } else {
-        const __divti3 = @import("compiler_rt/divti3.zig").__divti3;
-        @export(__divti3, .{ .name = "__divti3", .linkage = linkage });
-        const __modti3 = @import("compiler_rt/modti3.zig").__modti3;
-        @export(__modti3, .{ .name = "__modti3", .linkage = linkage });
-        const __multi3 = @import("compiler_rt/multi3.zig").__multi3;
-        @export(__multi3, .{ .name = "__multi3", .linkage = linkage });
-        const __udivti3 = @import("compiler_rt/udivti3.zig").__udivti3;
-        @export(__udivti3, .{ .name = "__udivti3", .linkage = linkage });
-        const __udivmodti4 = @import("compiler_rt/udivmodti4.zig").__udivmodti4;
-        @export(__udivmodti4, .{ .name = "__udivmodti4", .linkage = linkage });
-        const __umodti3 = @import("compiler_rt/umodti3.zig").__umodti3;
-        @export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
-    }
-    const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;
-    @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
-    const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;
-    @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
+        const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;
+        @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
+        const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;
+        @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
 
-    _ = @import("compiler_rt/atomics.zig");
+        _ = @import("compiler_rt/atomics.zig");
+    }
 }
 
 // Avoid dragging in the runtime safety mechanisms into this .o file,
 // unless we're trying to test this file.
-pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
+pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn {
     _ = error_return_trace;
     @setCold(true);
+    if (builtin.zig_is_stage2) {
+        while (true) {
+            @breakpoint();
+        }
+    }
     if (is_test) {
         std.debug.panic("{s}", .{msg});
     } else {
src/codegen/llvm/bindings.zig
@@ -601,6 +601,22 @@ pub const Builder = opaque {
         DestTy: *const Type,
         Name: [*:0]const u8,
     ) *const Value;
+
+    pub const buildFPTrunc = LLVMBuildFPTrunc;
+    extern fn LLVMBuildFPTrunc(
+        *const Builder,
+        Val: *const Value,
+        DestTy: *const Type,
+        Name: [*:0]const u8,
+    ) *const Value;
+
+    pub const buildFPExt = LLVMBuildFPExt;
+    extern fn LLVMBuildFPExt(
+        *const Builder,
+        Val: *const Value,
+        DestTy: *const Type,
+        Name: [*:0]const u8,
+    ) *const Value;
 };
 
 pub const IntPredicate = enum(c_uint) {
src/codegen/c.zig
@@ -954,7 +954,12 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .atomic_rmw       => try airAtomicRmw(f, inst),
             .atomic_load      => try airAtomicLoad(f, inst),
 
-            .int_to_float, .float_to_int => try airSimpleCast(f, inst),
+            .int_to_float,
+            .float_to_int,
+            .fptrunc,
+            .fpext,
+            .ptrtoint,
+            => try airSimpleCast(f, inst),
 
             .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)),
             .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)),
@@ -982,9 +987,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .unwrap_errunion_err_ptr     => try airUnwrapErrUnionErr(f, inst),
             .wrap_errunion_payload       => try airWrapErrUnionPay(f, inst),
             .wrap_errunion_err           => try airWrapErrUnionErr(f, inst),
-
-            .ptrtoint  => return f.fail("TODO: C backend: implement codegen for ptrtoint", .{}),
-            .floatcast => return f.fail("TODO: C backend: implement codegen for floatcast", .{}),
             // zig fmt: on
         };
         switch (result_value) {
src/codegen/llvm.zig
@@ -472,7 +472,18 @@ pub const Object = struct {
                 alias.setAliasee(llvm_fn);
             } else {
                 const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z);
-                _ = alias;
+                switch (exp.options.linkage) {
+                    .Internal => alias.setLinkage(.Internal),
+                    .Strong => alias.setLinkage(.External),
+                    .Weak => {
+                        if (is_extern) {
+                            alias.setLinkage(.ExternalWeak);
+                        } else {
+                            alias.setLinkage(.WeakODR);
+                        }
+                    },
+                    .LinkOnce => alias.setLinkage(.LinkOnceODR),
+                }
             }
         }
     }
@@ -1137,7 +1148,8 @@ pub const FuncGen = struct {
                 .cond_br        => try self.airCondBr(inst),
                 .intcast        => try self.airIntCast(inst),
                 .trunc          => try self.airTrunc(inst),
-                .floatcast      => try self.airFloatCast(inst),
+                .fptrunc        => try self.airFptrunc(inst),
+                .fpext          => try self.airFpext(inst),
                 .ptrtoint       => try self.airPtrToInt(inst),
                 .load           => try self.airLoad(inst),
                 .loop           => try self.airLoop(inst),
@@ -2060,12 +2072,26 @@ pub const FuncGen = struct {
         return self.builder.buildTrunc(operand, dest_llvm_ty, "");
     }
 
-    fn airFloatCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+    fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
         if (self.liveness.isUnused(inst))
             return null;
 
-        // TODO split floatcast AIR into float_widen and float_shorten
-        return self.todo("implement 'airFloatCast'", .{});
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const operand = try self.resolveInst(ty_op.operand);
+        const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
+
+        return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
+    }
+
+    fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+        if (self.liveness.isUnused(inst))
+            return null;
+
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const operand = try self.resolveInst(ty_op.operand);
+        const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
+
+        return self.builder.buildFPExt(operand, dest_llvm_ty, "");
     }
 
     fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/stage1/codegen.cpp
@@ -9325,6 +9325,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
     buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
     buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi);
     buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch);
+    buf_appendf(contents, "pub const stage2_arch: std.Target.Cpu.Arch = .%s;\n", cur_arch);
     buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os);
     buf_appendf(contents,
         "pub const target = std.Target{\n"
src/Air.zig
@@ -227,9 +227,12 @@ pub const Inst = struct {
         /// Indicates the program counter will never get to this instruction.
         /// Result type is always noreturn; no instructions in a block follow this one.
         unreach,
-        /// Convert from one float type to another.
+        /// Convert from a float type to a smaller one.
         /// Uses the `ty_op` field.
-        floatcast,
+        fptrunc,
+        /// Convert from a float type to a wider one.
+        /// Uses the `ty_op` field.
+        fpext,
         /// Returns an integer with a different type than the operand. The new type may have
         /// fewer, the same, or more bits than the operand type. However, the instruction
         /// guarantees that the same integer value fits in both types.
@@ -586,7 +589,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
         .not,
         .bitcast,
         .load,
-        .floatcast,
+        .fpext,
+        .fptrunc,
         .intcast,
         .trunc,
         .optional_payload,
src/AstGen.zig
@@ -2166,6 +2166,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
             .ensure_result_used,
             .ensure_result_non_error,
             .@"export",
+            .export_value,
             .set_eval_branch_quota,
             .ensure_err_payload_void,
             .atomic_store,
@@ -7095,32 +7096,55 @@ fn builtinCall(
                 .identifier => {
                     const ident_token = main_tokens[params[0]];
                     decl_name = try astgen.identAsString(ident_token);
-                    {
-                        var s = scope;
-                        while (true) switch (s.tag) {
-                            .local_val => {
-                                const local_val = s.cast(Scope.LocalVal).?;
-                                if (local_val.name == decl_name) {
-                                    local_val.used = true;
-                                    break;
-                                }
-                                s = local_val.parent;
-                            },
-                            .local_ptr => {
-                                const local_ptr = s.cast(Scope.LocalPtr).?;
-                                if (local_ptr.name == decl_name) {
-                                    if (!local_ptr.maybe_comptime)
-                                        return astgen.failNode(params[0], "unable to export runtime-known value", .{});
-                                    local_ptr.used = true;
-                                    break;
+
+                    var s = scope;
+                    var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
+                    while (true) switch (s.tag) {
+                        .local_val => {
+                            const local_val = s.cast(Scope.LocalVal).?;
+                            if (local_val.name == decl_name) {
+                                local_val.used = true;
+                                _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
+                                    .operand = local_val.inst,
+                                    .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]),
+                                });
+                                return rvalue(gz, rl, .void_value, node);
+                            }
+                            s = local_val.parent;
+                        },
+                        .local_ptr => {
+                            const local_ptr = s.cast(Scope.LocalPtr).?;
+                            if (local_ptr.name == decl_name) {
+                                if (!local_ptr.maybe_comptime)
+                                    return astgen.failNode(params[0], "unable to export runtime-known value", .{});
+                                local_ptr.used = true;
+                                const loaded = try gz.addUnNode(.load, local_ptr.ptr, node);
+                                _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
+                                    .operand = loaded,
+                                    .options = try comptimeExpr(gz, scope, .{ .coerced_ty = .export_options_type }, params[1]),
+                                });
+                                return rvalue(gz, rl, .void_value, node);
+                            }
+                            s = local_ptr.parent;
+                        },
+                        .gen_zir => s = s.cast(GenZir).?.parent,
+                        .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
+                        .namespace => {
+                            const ns = s.cast(Scope.Namespace).?;
+                            if (ns.decls.get(decl_name)) |i| {
+                                if (found_already) |f| {
+                                    return astgen.failNodeNotes(node, "ambiguous reference", .{}, &.{
+                                        try astgen.errNoteNode(f, "declared here", .{}),
+                                        try astgen.errNoteNode(i, "also declared here", .{}),
+                                    });
                                 }
-                                s = local_ptr.parent;
-                            },
-                            .gen_zir => s = s.cast(GenZir).?.parent,
-                            .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
-                            .namespace, .top => break,
-                        };
-                    }
+                                // We found a match but must continue looking for ambiguous references to decls.
+                                found_already = i;
+                            }
+                            s = ns.parent;
+                        },
+                        .top => break,
+                    };
                 },
                 .field_access => {
                     const namespace_node = node_datas[params[0]].lhs;
src/codegen.zig
@@ -859,7 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     .call            => try self.airCall(inst),
                     .cond_br         => try self.airCondBr(inst),
                     .dbg_stmt        => try self.airDbgStmt(inst),
-                    .floatcast       => try self.airFloatCast(inst),
+                    .fptrunc         => try self.airFptrunc(inst),
+                    .fpext           => try self.airFpext(inst),
                     .intcast         => try self.airIntCast(inst),
                     .trunc           => try self.airTrunc(inst),
                     .bool_to_int     => try self.airBoolToInt(inst),
@@ -1172,10 +1173,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
             return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
         }
 
-        fn airFloatCast(self: *Self, inst: Air.Inst.Index) !void {
+        fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
             const ty_op = self.air.instructions.items(.data)[inst].ty_op;
             const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
-                else => return self.fail("TODO implement floatCast for {}", .{self.target.cpu.arch}),
+                else => return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}),
+            };
+            return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+        }
+
+        fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
+            const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+            const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
+                else => return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}),
             };
             return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
         }
src/Liveness.zig
@@ -274,7 +274,8 @@ fn analyzeInst(
         .not,
         .bitcast,
         .load,
-        .floatcast,
+        .fpext,
+        .fptrunc,
         .intcast,
         .trunc,
         .optional_payload,
src/Module.zig
@@ -2389,6 +2389,7 @@ pub fn deinit(mod: *Module) void {
 fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
     for (export_list) |exp| {
         gpa.free(exp.options.name);
+        if (exp.options.section) |s| gpa.free(s);
         gpa.destroy(exp);
     }
     gpa.free(export_list);
@@ -3317,7 +3318,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
                     return mod.fail(&block_scope.base, export_src, "export of inline function", .{});
                 }
                 // The scope needs to have the decl in it.
-                try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl);
+                const options: std.builtin.ExportOptions = .{ .name = mem.spanZ(decl.name) };
+                try mod.analyzeExport(&block_scope.base, export_src, options, decl);
             }
             return type_changed or is_inline != prev_is_inline;
         }
@@ -3376,7 +3378,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
     if (decl.is_exported) {
         const export_src = src; // TODO point to the export token
         // The scope needs to have the decl in it.
-        try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl);
+        const options: std.builtin.ExportOptions = .{ .name = mem.spanZ(decl.name) };
+        try mod.analyzeExport(&block_scope.base, export_src, options, decl);
     }
 
     return type_changed;
@@ -4119,7 +4122,7 @@ pub fn analyzeExport(
     mod: *Module,
     scope: *Scope,
     src: LazySrcLoc,
-    borrowed_symbol_name: []const u8,
+    borrowed_options: std.builtin.ExportOptions,
     exported_decl: *Decl,
 ) !void {
     try mod.ensureDeclAnalyzed(exported_decl);
@@ -4128,23 +4131,32 @@ pub fn analyzeExport(
         else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}),
     }
 
-    try mod.decl_exports.ensureUnusedCapacity(mod.gpa, 1);
-    try mod.export_owners.ensureUnusedCapacity(mod.gpa, 1);
+    const gpa = mod.gpa;
+
+    try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
+    try mod.export_owners.ensureUnusedCapacity(gpa, 1);
 
-    const new_export = try mod.gpa.create(Export);
-    errdefer mod.gpa.destroy(new_export);
+    const new_export = try gpa.create(Export);
+    errdefer gpa.destroy(new_export);
 
-    const symbol_name = try mod.gpa.dupe(u8, borrowed_symbol_name);
-    errdefer mod.gpa.free(symbol_name);
+    const symbol_name = try gpa.dupe(u8, borrowed_options.name);
+    errdefer gpa.free(symbol_name);
+
+    const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null;
+    errdefer if (section) |s| gpa.free(s);
 
     const owner_decl = scope.ownerDecl().?;
 
     log.debug("exporting Decl '{s}' as symbol '{s}' from Decl '{s}'", .{
-        exported_decl.name, borrowed_symbol_name, owner_decl.name,
+        exported_decl.name, symbol_name, owner_decl.name,
     });
 
     new_export.* = .{
-        .options = .{ .name = symbol_name },
+        .options = .{
+            .name = symbol_name,
+            .linkage = borrowed_options.linkage,
+            .section = section,
+        },
         .src = src,
         .link = switch (mod.comp.bin_file.tag) {
             .coff => .{ .coff = {} },
@@ -4165,18 +4177,18 @@ pub fn analyzeExport(
     if (!eo_gop.found_existing) {
         eo_gop.value_ptr.* = &[0]*Export{};
     }
-    eo_gop.value_ptr.* = try mod.gpa.realloc(eo_gop.value_ptr.*, eo_gop.value_ptr.len + 1);
+    eo_gop.value_ptr.* = try gpa.realloc(eo_gop.value_ptr.*, eo_gop.value_ptr.len + 1);
     eo_gop.value_ptr.*[eo_gop.value_ptr.len - 1] = new_export;
-    errdefer eo_gop.value_ptr.* = mod.gpa.shrink(eo_gop.value_ptr.*, eo_gop.value_ptr.len - 1);
+    errdefer eo_gop.value_ptr.* = gpa.shrink(eo_gop.value_ptr.*, eo_gop.value_ptr.len - 1);
 
     // Add to exported_decl table.
     const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl);
     if (!de_gop.found_existing) {
         de_gop.value_ptr.* = &[0]*Export{};
     }
-    de_gop.value_ptr.* = try mod.gpa.realloc(de_gop.value_ptr.*, de_gop.value_ptr.len + 1);
+    de_gop.value_ptr.* = try gpa.realloc(de_gop.value_ptr.*, de_gop.value_ptr.len + 1);
     de_gop.value_ptr.*[de_gop.value_ptr.len - 1] = new_export;
-    errdefer de_gop.value_ptr.* = mod.gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
+    errdefer de_gop.value_ptr.* = gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
 }
 
 /// Takes ownership of `name` even if it returns an error.
src/print_air.zig
@@ -156,7 +156,8 @@ const Writer = struct {
             .not,
             .bitcast,
             .load,
-            .floatcast,
+            .fptrunc,
+            .fpext,
             .intcast,
             .trunc,
             .optional_payload,
src/print_zir.zig
@@ -285,6 +285,7 @@ const Writer = struct {
             => try self.writePlNodeBin(stream, inst),
 
             .@"export" => try self.writePlNodeExport(stream, inst),
+            .export_value => try self.writePlNodeExportValue(stream, inst),
 
             .call,
             .call_chkused,
@@ -611,6 +612,17 @@ const Writer = struct {
         try self.writeSrc(stream, inst_data.src());
     }
 
+    fn writePlNodeExportValue(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
+        const inst_data = self.code.instructions.items(.data)[inst].pl_node;
+        const extra = self.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
+
+        try self.writeInstRef(stream, extra.operand);
+        try stream.writeAll(", ");
+        try self.writeInstRef(stream, extra.options);
+        try stream.writeAll(") ");
+        try self.writeSrc(stream, inst_data.src());
+    }
+
     fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
         const inst_data = self.code.instructions.items(.data)[inst].pl_node;
         const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
src/Sema.zig
@@ -458,6 +458,11 @@ pub fn analyzeBody(
                 i += 1;
                 continue;
             },
+            .export_value => {
+                try sema.zirExportValue(block, inst);
+                i += 1;
+                continue;
+            },
             .set_align_stack => {
                 try sema.zirSetAlignStack(block, inst);
                 i += 1;
@@ -2392,30 +2397,33 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
     const src = inst_data.src();
-    const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
-    const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+    const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+    const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const decl_name = sema.code.nullTerminatedString(extra.decl_name);
     if (extra.namespace != .none) {
         return sema.mod.fail(&block.base, src, "TODO: implement exporting with field access", .{});
     }
-    const decl = try sema.lookupIdentifier(block, lhs_src, decl_name);
-    const options = try sema.resolveInstConst(block, rhs_src, extra.options);
-    const struct_obj = options.ty.castTag(.@"struct").?.data;
-    const fields = options.val.castTag(.@"struct").?.data[0..struct_obj.fields.count()];
-    const name_index = struct_obj.fields.getIndex("name").?;
-    const linkage_index = struct_obj.fields.getIndex("linkage").?;
-    const section_index = struct_obj.fields.getIndex("section").?;
-    const export_name = try fields[name_index].toAllocatedBytes(sema.arena);
-    const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage);
+    const decl = try sema.lookupIdentifier(block, operand_src, decl_name);
+    const options = try sema.resolveExportOptions(block, options_src, extra.options);
+    try sema.mod.analyzeExport(&block.base, src, options, decl);
+}
 
-    if (linkage != .Strong) {
-        return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{});
-    }
-    if (!fields[section_index].isNull()) {
-        return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{});
-    }
+fn zirExportValue(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
+    const tracy = trace(@src());
+    defer tracy.end();
 
-    try sema.mod.analyzeExport(&block.base, src, export_name, decl);
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
+    const src = inst_data.src();
+    const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+    const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+    const operand = try sema.resolveInstConst(block, operand_src, extra.operand);
+    const options = try sema.resolveExportOptions(block, options_src, extra.options);
+    const decl = switch (operand.val.tag()) {
+        .function => operand.val.castTag(.function).?.data.owner_decl,
+        else => return sema.mod.fail(&block.base, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it.
+    };
+    try sema.mod.analyzeExport(&block.base, src, options, decl);
 }
 
 fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
@@ -4516,11 +4524,18 @@ fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
 
     if (try sema.isComptimeKnown(block, operand_src, operand)) {
         return sema.coerce(block, dest_type, operand, operand_src);
-    } else if (dest_is_comptime_float) {
+    }
+    if (dest_is_comptime_float) {
         return sema.mod.fail(&block.base, src, "unable to cast runtime value to 'comptime_float'", .{});
     }
-
-    return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten float", .{});
+    const target = sema.mod.getTarget();
+    const src_bits = operand_ty.floatBits(target);
+    const dst_bits = dest_type.floatBits(target);
+    if (dst_bits >= src_bits) {
+        return sema.coerce(block, dest_type, operand, operand_src);
+    }
+    try sema.requireRuntimeBlock(block, operand_src);
+    return block.addTyOp(.fptrunc, dest_type, operand);
 }
 
 fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -7936,6 +7951,31 @@ fn checkAtomicOperandType(
     }
 }
 
+fn resolveExportOptions(
+    sema: *Sema,
+    block: *Scope.Block,
+    src: LazySrcLoc,
+    zir_ref: Zir.Inst.Ref,
+) CompileError!std.builtin.ExportOptions {
+    const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions");
+    const air_ref = sema.resolveInst(zir_ref);
+    const coerced = try sema.coerce(block, export_options_ty, air_ref, src);
+    const val = try sema.resolveConstValue(block, src, coerced);
+    const fields = val.castTag(.@"struct").?.data;
+    const struct_obj = export_options_ty.castTag(.@"struct").?.data;
+    const name_index = struct_obj.fields.getIndex("name").?;
+    const linkage_index = struct_obj.fields.getIndex("linkage").?;
+    const section_index = struct_obj.fields.getIndex("section").?;
+    if (!fields[section_index].isNull()) {
+        return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{});
+    }
+    return std.builtin.ExportOptions{
+        .name = try fields[name_index].toAllocatedBytes(sema.arena),
+        .linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage),
+        .section = null, // TODO
+    };
+}
+
 fn resolveAtomicOrder(
     sema: *Sema,
     block: *Scope.Block,
@@ -9581,7 +9621,7 @@ fn coerce(
                 const dst_bits = dest_type.floatBits(target);
                 if (dst_bits >= src_bits) {
                     try sema.requireRuntimeBlock(block, inst_src);
-                    return block.addTyOp(.floatcast, dest_type, inst);
+                    return block.addTyOp(.fpext, dest_type, inst);
                 }
             }
         },
@@ -9729,35 +9769,53 @@ fn coerceNum(
     const target = sema.mod.getTarget();
 
     switch (dst_zig_tag) {
-        .ComptimeInt, .Int => {
-            if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
+        .ComptimeInt, .Int => switch (src_zig_tag) {
+            .Float, .ComptimeFloat => {
                 if (val.floatHasFraction()) {
-                    return sema.mod.fail(&block.base, inst_src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst_ty });
+                    return sema.mod.fail(&block.base, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_type });
                 }
                 return sema.mod.fail(&block.base, inst_src, "TODO float to int", .{});
-            } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
+            },
+            .Int, .ComptimeInt => {
                 if (!val.intFitsInType(dest_type, target)) {
                     return sema.mod.fail(&block.base, inst_src, "type {} cannot represent integer value {}", .{ dest_type, val });
                 }
                 return try sema.addConstant(dest_type, val);
-            }
+            },
+            else => {},
         },
-        .ComptimeFloat, .Float => {
-            if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
-                const res = val.floatCast(sema.arena, dest_type) catch |err| switch (err) {
-                    error.Overflow => return sema.mod.fail(
+        .ComptimeFloat, .Float => switch (src_zig_tag) {
+            .ComptimeFloat => {
+                const result_val = try val.floatCast(sema.arena, dest_type);
+                return try sema.addConstant(dest_type, result_val);
+            },
+            .Float => {
+                const result_val = try val.floatCast(sema.arena, dest_type);
+                if (!val.eql(result_val, dest_type)) {
+                    return sema.mod.fail(
                         &block.base,
                         inst_src,
-                        "cast of value {} to type '{}' loses information",
-                        .{ val, dest_type },
-                    ),
-                    error.OutOfMemory => return error.OutOfMemory,
-                };
-                return try sema.addConstant(dest_type, res);
-            } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
+                        "type {} cannot represent float value {}",
+                        .{ dest_type, val },
+                    );
+                }
+                return try sema.addConstant(dest_type, result_val);
+            },
+            .Int, .ComptimeInt => {
                 const result_val = try val.intToFloat(sema.arena, dest_type, target);
+                // TODO implement this compile error
+                //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
+                //if (!int_again_val.eql(val, inst_ty)) {
+                //    return sema.mod.fail(
+                //        &block.base,
+                //        inst_src,
+                //        "type {} cannot represent integer value {}",
+                //        .{ dest_type, val },
+                //    );
+                //}
                 return try sema.addConstant(dest_type, result_val);
-            }
+            },
+            else => {},
         },
         else => {},
     }
src/value.zig
@@ -1041,30 +1041,15 @@ pub const Value = extern union {
         }
     }
 
-    /// Converts an integer or a float to a float.
-    /// Returns `error.Overflow` if the value does not fit in the new type.
-    pub fn floatCast(self: Value, allocator: *Allocator, dest_ty: Type) !Value {
+    /// Converts an integer or a float to a float. May result in a loss of information.
+    /// Caller can find out by equality checking the result against the operand.
+    pub fn floatCast(self: Value, arena: *Allocator, dest_ty: Type) !Value {
         switch (dest_ty.tag()) {
-            .f16 => {
-                const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16));
-                if (!self.eql(res, dest_ty))
-                    return error.Overflow;
-                return res;
-            },
-            .f32 => {
-                const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32));
-                if (!self.eql(res, dest_ty))
-                    return error.Overflow;
-                return res;
-            },
-            .f64 => {
-                const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64));
-                if (!self.eql(res, dest_ty))
-                    return error.Overflow;
-                return res;
-            },
+            .f16 => return Value.Tag.float_16.create(arena, self.toFloat(f16)),
+            .f32 => return Value.Tag.float_32.create(arena, self.toFloat(f32)),
+            .f64 => return Value.Tag.float_64.create(arena, self.toFloat(f64)),
             .f128, .comptime_float, .c_longdouble => {
-                return Value.Tag.float_128.create(allocator, self.toFloat(f128));
+                return Value.Tag.float_128.create(arena, self.toFloat(f128));
             },
             else => unreachable,
         }
src/Zir.zig
@@ -319,9 +319,13 @@ pub const Inst = struct {
         /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
         error_value,
         /// Implements the `@export` builtin function, based on either an identifier to a Decl,
-        /// or field access of a Decl.
+        /// or field access of a Decl. The thing being exported is the Decl.
         /// Uses the `pl_node` union field. Payload is `Export`.
         @"export",
+        /// Implements the `@export` builtin function, based on a comptime-known value.
+        /// The thing being exported is the comptime-known value which is the operand.
+        /// Uses the `pl_node` union field. Payload is `ExportValue`.
+        export_value,
         /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
         /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
         /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
@@ -1010,6 +1014,7 @@ pub const Inst = struct {
                 .ensure_result_used,
                 .ensure_result_non_error,
                 .@"export",
+                .export_value,
                 .field_ptr,
                 .field_val,
                 .field_ptr_named,
@@ -1273,6 +1278,7 @@ pub const Inst = struct {
                 .error_union_type = .pl_node,
                 .error_value = .str_tok,
                 .@"export" = .pl_node,
+                .export_value = .pl_node,
                 .field_ptr = .pl_node,
                 .field_val = .pl_node,
                 .field_ptr_named = .pl_node,
@@ -2843,6 +2849,12 @@ pub const Inst = struct {
         options: Ref,
     };
 
+    pub const ExportValue = struct {
+        /// The comptime value to export.
+        operand: Ref,
+        options: Ref,
+    };
+
     /// Trailing: `CompileErrors.Item` for each `items_len`.
     pub const CompileErrors = struct {
         items_len: u32,
test/behavior/union.zig
@@ -2,816 +2,3 @@ const std = @import("std");
 const expect = std.testing.expect;
 const expectEqual = std.testing.expectEqual;
 const Tag = std.meta.Tag;
-
-const Value = union(enum) {
-    Int: u64,
-    Array: [9]u8,
-};
-
-const Agg = struct {
-    val1: Value,
-    val2: Value,
-};
-
-const v1 = Value{ .Int = 1234 };
-const v2 = Value{ .Array = [_]u8{3} ** 9 };
-
-const err = @as(anyerror!Agg, Agg{
-    .val1 = v1,
-    .val2 = v2,
-});
-
-const array = [_]Value{
-    v1,
-    v2,
-    v1,
-    v2,
-};
-
-test "unions embedded in aggregate types" {
-    switch (array[1]) {
-        Value.Array => |arr| try expect(arr[4] == 3),
-        else => unreachable,
-    }
-    switch ((err catch unreachable).val1) {
-        Value.Int => |x| try expect(x == 1234),
-        else => unreachable,
-    }
-}
-
-const Foo = union {
-    float: f64,
-    int: i32,
-};
-
-test "basic unions" {
-    var foo = Foo{ .int = 1 };
-    try expect(foo.int == 1);
-    foo = Foo{ .float = 12.34 };
-    try expect(foo.float == 12.34);
-}
-
-test "comptime union field access" {
-    comptime {
-        var foo = Foo{ .int = 0 };
-        try expect(foo.int == 0);
-
-        foo = Foo{ .float = 42.42 };
-        try expect(foo.float == 42.42);
-    }
-}
-
-test "init union with runtime value" {
-    var foo: Foo = undefined;
-
-    setFloat(&foo, 12.34);
-    try expect(foo.float == 12.34);
-
-    setInt(&foo, 42);
-    try expect(foo.int == 42);
-}
-
-fn setFloat(foo: *Foo, x: f64) void {
-    foo.* = Foo{ .float = x };
-}
-
-fn setInt(foo: *Foo, x: i32) void {
-    foo.* = Foo{ .int = x };
-}
-
-const FooExtern = extern union {
-    float: f64,
-    int: i32,
-};
-
-test "basic extern unions" {
-    var foo = FooExtern{ .int = 1 };
-    try expect(foo.int == 1);
-    foo.float = 12.34;
-    try expect(foo.float == 12.34);
-}
-
-const Letter = enum {
-    A,
-    B,
-    C,
-};
-const Payload = union(Letter) {
-    A: i32,
-    B: f64,
-    C: bool,
-};
-
-test "union with specified enum tag" {
-    try doTest();
-    comptime try doTest();
-}
-
-fn doTest() error{TestUnexpectedResult}!void {
-    try expect((try bar(Payload{ .A = 1234 })) == -10);
-}
-
-fn bar(value: Payload) error{TestUnexpectedResult}!i32 {
-    try expect(@as(Letter, value) == Letter.A);
-    return switch (value) {
-        Payload.A => |x| return x - 1244,
-        Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,
-        Payload.C => |x| if (x) @as(i32, 30) else 31,
-    };
-}
-
-const MultipleChoice = union(enum(u32)) {
-    A = 20,
-    B = 40,
-    C = 60,
-    D = 1000,
-};
-test "simple union(enum(u32))" {
-    var x = MultipleChoice.C;
-    try expect(x == MultipleChoice.C);
-    try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60);
-}
-
-const MultipleChoice2 = union(enum(u32)) {
-    Unspecified1: i32,
-    A: f32 = 20,
-    Unspecified2: void,
-    B: bool = 40,
-    Unspecified3: i32,
-    C: i8 = 60,
-    Unspecified4: void,
-    D: void = 1000,
-    Unspecified5: i32,
-};
-
-test "union(enum(u32)) with specified and unspecified tag values" {
-    comptime try expect(Tag(Tag(MultipleChoice2)) == u32);
-    try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
-    comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
-    try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60);
-    try expect(1123 == switch (x) {
-        MultipleChoice2.A => 1,
-        MultipleChoice2.B => 2,
-        MultipleChoice2.C => |v| @as(i32, 1000) + v,
-        MultipleChoice2.D => 4,
-        MultipleChoice2.Unspecified1 => 5,
-        MultipleChoice2.Unspecified2 => 6,
-        MultipleChoice2.Unspecified3 => 7,
-        MultipleChoice2.Unspecified4 => 8,
-        MultipleChoice2.Unspecified5 => 9,
-    });
-}
-
-const ExternPtrOrInt = extern union {
-    ptr: *u8,
-    int: u64,
-};
-test "extern union size" {
-    comptime try expect(@sizeOf(ExternPtrOrInt) == 8);
-}
-
-const PackedPtrOrInt = packed union {
-    ptr: *u8,
-    int: u64,
-};
-test "extern union size" {
-    comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
-}
-
-const ZeroBits = union {
-    OnlyField: void,
-};
-test "union with only 1 field which is void should be zero bits" {
-    comptime try expect(@sizeOf(ZeroBits) == 0);
-}
-
-const TheTag = enum {
-    A,
-    B,
-    C,
-};
-const TheUnion = union(TheTag) {
-    A: i32,
-    B: i32,
-    C: i32,
-};
-test "union field access gives the enum values" {
-    try expect(TheUnion.A == TheTag.A);
-    try expect(TheUnion.B == TheTag.B);
-    try expect(TheUnion.C == TheTag.C);
-}
-
-test "cast union to tag type of union" {
-    try testCastUnionToTag(TheUnion{ .B = 1234 });
-    comptime try testCastUnionToTag(TheUnion{ .B = 1234 });
-}
-
-fn testCastUnionToTag(x: TheUnion) !void {
-    try expect(@as(TheTag, x) == TheTag.B);
-}
-
-test "cast tag type of union to union" {
-    var x: Value2 = Letter2.B;
-    try expect(@as(Letter2, x) == Letter2.B);
-}
-const Letter2 = enum {
-    A,
-    B,
-    C,
-};
-const Value2 = union(Letter2) {
-    A: i32,
-    B,
-    C,
-};
-
-test "implicit cast union to its tag type" {
-    var x: Value2 = Letter2.B;
-    try expect(x == Letter2.B);
-    try giveMeLetterB(x);
-}
-fn giveMeLetterB(x: Letter2) !void {
-    try expect(x == Value2.B);
-}
-
-pub const PackThis = union(enum) {
-    Invalid: bool,
-    StringLiteral: u2,
-};
-
-test "constant packed union" {
-    try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});
-}
-
-fn testConstPackedUnion(expected_tokens: []const PackThis) !void {
-    try expect(expected_tokens[0].StringLiteral == 1);
-}
-
-test "switch on union with only 1 field" {
-    var r: PartialInst = undefined;
-    r = PartialInst.Compiled;
-    switch (r) {
-        PartialInst.Compiled => {
-            var z: PartialInstWithPayload = undefined;
-            z = PartialInstWithPayload{ .Compiled = 1234 };
-            switch (z) {
-                PartialInstWithPayload.Compiled => |x| {
-                    try expect(x == 1234);
-                    return;
-                },
-            }
-        },
-    }
-    unreachable;
-}
-
-const PartialInst = union(enum) {
-    Compiled,
-};
-
-const PartialInstWithPayload = union(enum) {
-    Compiled: i32,
-};
-
-test "access a member of tagged union with conflicting enum tag name" {
-    const Bar = union(enum) {
-        A: A,
-        B: B,
-
-        const A = u8;
-        const B = void;
-    };
-
-    comptime try expect(Bar.A == u8);
-}
-
-test "tagged union initialization with runtime void" {
-    try expect(testTaggedUnionInit({}));
-}
-
-const TaggedUnionWithAVoid = union(enum) {
-    A,
-    B: i32,
-};
-
-fn testTaggedUnionInit(x: anytype) bool {
-    const y = TaggedUnionWithAVoid{ .A = x };
-    return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A;
-}
-
-pub const UnionEnumNoPayloads = union(enum) {
-    A,
-    B,
-};
-
-test "tagged union with no payloads" {
-    const a = UnionEnumNoPayloads{ .B = {} };
-    switch (a) {
-        Tag(UnionEnumNoPayloads).A => @panic("wrong"),
-        Tag(UnionEnumNoPayloads).B => {},
-    }
-}
-
-test "union with only 1 field casted to its enum type" {
-    const Literal = union(enum) {
-        Number: f64,
-        Bool: bool,
-    };
-
-    const Expr = union(enum) {
-        Literal: Literal,
-    };
-
-    var e = Expr{ .Literal = Literal{ .Bool = true } };
-    const ExprTag = Tag(Expr);
-    comptime try expect(Tag(ExprTag) == u0);
-    var t = @as(ExprTag, e);
-    try expect(t == Expr.Literal);
-}
-
-test "union with only 1 field casted to its enum type which has enum value specified" {
-    const Literal = union(enum) {
-        Number: f64,
-        Bool: bool,
-    };
-
-    const ExprTag = enum(comptime_int) {
-        Literal = 33,
-    };
-
-    const Expr = union(ExprTag) {
-        Literal: Literal,
-    };
-
-    var e = Expr{ .Literal = Literal{ .Bool = true } };
-    comptime try expect(Tag(ExprTag) == comptime_int);
-    var t = @as(ExprTag, e);
-    try expect(t == Expr.Literal);
-    try expect(@enumToInt(t) == 33);
-    comptime try expect(@enumToInt(t) == 33);
-}
-
-test "@enumToInt works on unions" {
-    const Bar = union(enum) {
-        A: bool,
-        B: u8,
-        C,
-    };
-
-    const a = Bar{ .A = true };
-    var b = Bar{ .B = undefined };
-    var c = Bar.C;
-    try expect(@enumToInt(a) == 0);
-    try expect(@enumToInt(b) == 1);
-    try expect(@enumToInt(c) == 2);
-}
-
-const Attribute = union(enum) {
-    A: bool,
-    B: u8,
-};
-
-fn setAttribute(attr: Attribute) void {
-    _ = attr;
-}
-
-fn Setter(attr: Attribute) type {
-    return struct {
-        fn set() void {
-            setAttribute(attr);
-        }
-    };
-}
-
-test "comptime union field value equality" {
-    const a0 = Setter(Attribute{ .A = false });
-    const a1 = Setter(Attribute{ .A = true });
-    const a2 = Setter(Attribute{ .A = false });
-
-    const b0 = Setter(Attribute{ .B = 5 });
-    const b1 = Setter(Attribute{ .B = 9 });
-    const b2 = Setter(Attribute{ .B = 5 });
-
-    try expect(a0 == a0);
-    try expect(a1 == a1);
-    try expect(a0 == a2);
-
-    try expect(b0 == b0);
-    try expect(b1 == b1);
-    try expect(b0 == b2);
-
-    try expect(a0 != b0);
-    try expect(a0 != a1);
-    try expect(b0 != b1);
-}
-
-test "return union init with void payload" {
-    const S = struct {
-        fn entry() !void {
-            try expect(func().state == State.one);
-        }
-        const Outer = union(enum) {
-            state: State,
-        };
-        const State = union(enum) {
-            one: void,
-            two: u32,
-        };
-        fn func() Outer {
-            return Outer{ .state = State{ .one = {} } };
-        }
-    };
-    try S.entry();
-    comptime try S.entry();
-}
-
-test "@unionInit can modify a union type" {
-    const UnionInitEnum = union(enum) {
-        Boolean: bool,
-        Byte: u8,
-    };
-
-    var value: UnionInitEnum = undefined;
-
-    value = @unionInit(UnionInitEnum, "Boolean", true);
-    try expect(value.Boolean == true);
-    value.Boolean = false;
-    try expect(value.Boolean == false);
-
-    value = @unionInit(UnionInitEnum, "Byte", 2);
-    try expect(value.Byte == 2);
-    value.Byte = 3;
-    try expect(value.Byte == 3);
-}
-
-test "@unionInit can modify a pointer value" {
-    const UnionInitEnum = union(enum) {
-        Boolean: bool,
-        Byte: u8,
-    };
-
-    var value: UnionInitEnum = undefined;
-    var value_ptr = &value;
-
-    value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
-    try expect(value.Boolean == true);
-
-    value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
-    try expect(value.Byte == 2);
-}
-
-test "union no tag with struct member" {
-    const Struct = struct {};
-    const Union = union {
-        s: Struct,
-        pub fn foo(self: *@This()) void {
-            _ = self;
-        }
-    };
-    var u = Union{ .s = Struct{} };
-    u.foo();
-}
-
-fn testComparison() !void {
-    var x = Payload{ .A = 42 };
-    try expect(x == .A);
-    try expect(x != .B);
-    try expect(x != .C);
-    try expect((x == .B) == false);
-    try expect((x == .C) == false);
-    try expect((x != .A) == false);
-}
-
-test "comparison between union and enum literal" {
-    try testComparison();
-    comptime try testComparison();
-}
-
-test "packed union generates correctly aligned LLVM type" {
-    const U = packed union {
-        f1: fn () error{TestUnexpectedResult}!void,
-        f2: u32,
-    };
-    var foo = [_]U{
-        U{ .f1 = doTest },
-        U{ .f2 = 0 },
-    };
-    try foo[0].f1();
-}
-
-test "union with one member defaults to u0 tag type" {
-    const U0 = union(enum) {
-        X: u32,
-    };
-    comptime try expect(Tag(Tag(U0)) == u0);
-}
-
-test "union with comptime_int tag" {
-    const Union = union(enum(comptime_int)) {
-        X: u32,
-        Y: u16,
-        Z: u8,
-    };
-    comptime try expect(Tag(Tag(Union)) == comptime_int);
-}
-
-test "extern union doesn't trigger field check at comptime" {
-    const U = extern union {
-        x: u32,
-        y: u8,
-    };
-
-    const x = U{ .x = 0x55AAAA55 };
-    comptime try expect(x.y == 0x55);
-}
-
-const Foo1 = union(enum) {
-    f: struct {
-        x: usize,
-    },
-};
-var glbl: Foo1 = undefined;
-
-test "global union with single field is correctly initialized" {
-    glbl = Foo1{
-        .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
-    };
-    try expect(glbl.f.x == 123);
-}
-
-pub const FooUnion = union(enum) {
-    U0: usize,
-    U1: u8,
-};
-
-var glbl_array: [2]FooUnion = undefined;
-
-test "initialize global array of union" {
-    glbl_array[1] = FooUnion{ .U1 = 2 };
-    glbl_array[0] = FooUnion{ .U0 = 1 };
-    try expect(glbl_array[0].U0 == 1);
-    try expect(glbl_array[1].U1 == 2);
-}
-
-test "anonymous union literal syntax" {
-    const S = struct {
-        const Number = union {
-            int: i32,
-            float: f64,
-        };
-
-        fn doTheTest() !void {
-            var i: Number = .{ .int = 42 };
-            var f = makeNumber();
-            try expect(i.int == 42);
-            try expect(f.float == 12.34);
-        }
-
-        fn makeNumber() Number {
-            return .{ .float = 12.34 };
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "update the tag value for zero-sized unions" {
-    const S = union(enum) {
-        U0: void,
-        U1: void,
-    };
-    var x = S{ .U0 = {} };
-    try expect(x == .U0);
-    x = S{ .U1 = {} };
-    try expect(x == .U1);
-}
-
-test "function call result coerces from tagged union to the tag" {
-    const S = struct {
-        const Arch = union(enum) {
-            One,
-            Two: usize,
-        };
-
-        const ArchTag = Tag(Arch);
-
-        fn doTheTest() !void {
-            var x: ArchTag = getArch1();
-            try expect(x == .One);
-
-            var y: ArchTag = getArch2();
-            try expect(y == .Two);
-        }
-
-        pub fn getArch1() Arch {
-            return .One;
-        }
-
-        pub fn getArch2() Arch {
-            return .{ .Two = 99 };
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "0-sized extern union definition" {
-    const U = extern union {
-        a: void,
-        const f = 1;
-    };
-
-    try expect(U.f == 1);
-}
-
-test "union initializer generates padding only if needed" {
-    const U = union(enum) {
-        A: u24,
-    };
-
-    var v = U{ .A = 532 };
-    try expect(v.A == 532);
-}
-
-test "runtime tag name with single field" {
-    const U = union(enum) {
-        A: i32,
-    };
-
-    var v = U{ .A = 42 };
-    try expect(std.mem.eql(u8, @tagName(v), "A"));
-}
-
-test "cast from anonymous struct to union" {
-    const S = struct {
-        const U = union(enum) {
-            A: u32,
-            B: []const u8,
-            C: void,
-        };
-        fn doTheTest() !void {
-            var y: u32 = 42;
-            const t0 = .{ .A = 123 };
-            const t1 = .{ .B = "foo" };
-            const t2 = .{ .C = {} };
-            const t3 = .{ .A = y };
-            const x0: U = t0;
-            var x1: U = t1;
-            const x2: U = t2;
-            var x3: U = t3;
-            try expect(x0.A == 123);
-            try expect(std.mem.eql(u8, x1.B, "foo"));
-            try expect(x2 == .C);
-            try expect(x3.A == y);
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "cast from pointer to anonymous struct to pointer to union" {
-    const S = struct {
-        const U = union(enum) {
-            A: u32,
-            B: []const u8,
-            C: void,
-        };
-        fn doTheTest() !void {
-            var y: u32 = 42;
-            const t0 = &.{ .A = 123 };
-            const t1 = &.{ .B = "foo" };
-            const t2 = &.{ .C = {} };
-            const t3 = &.{ .A = y };
-            const x0: *const U = t0;
-            var x1: *const U = t1;
-            const x2: *const U = t2;
-            var x3: *const U = t3;
-            try expect(x0.A == 123);
-            try expect(std.mem.eql(u8, x1.B, "foo"));
-            try expect(x2.* == .C);
-            try expect(x3.A == y);
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "method call on an empty union" {
-    const S = struct {
-        const MyUnion = union(MyUnionTag) {
-            pub const MyUnionTag = enum { X1, X2 };
-            X1: [0]u8,
-            X2: [0]u8,
-
-            pub fn useIt(self: *@This()) bool {
-                _ = self;
-                return true;
-            }
-        };
-
-        fn doTheTest() !void {
-            var u = MyUnion{ .X1 = [0]u8{} };
-            try expect(u.useIt());
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "switching on non exhaustive union" {
-    const S = struct {
-        const E = enum(u8) {
-            a,
-            b,
-            _,
-        };
-        const U = union(E) {
-            a: i32,
-            b: u32,
-        };
-        fn doTheTest() !void {
-            var a = U{ .a = 2 };
-            switch (a) {
-                .a => |val| try expect(val == 2),
-                .b => unreachable,
-            }
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "containers with single-field enums" {
-    const S = struct {
-        const A = union(enum) { f1 };
-        const B = union(enum) { f1: void };
-        const C = struct { a: A };
-        const D = struct { a: B };
-
-        fn doTheTest() !void {
-            var array1 = [1]A{A{ .f1 = {} }};
-            var array2 = [1]B{B{ .f1 = {} }};
-            try expect(array1[0] == .f1);
-            try expect(array2[0] == .f1);
-
-            var struct1 = C{ .a = A{ .f1 = {} } };
-            var struct2 = D{ .a = B{ .f1 = {} } };
-            try expect(struct1.a == .f1);
-            try expect(struct2.a == .f1);
-        }
-    };
-
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "@unionInit on union w/ tag but no fields" {
-    const S = struct {
-        const Type = enum(u8) { no_op = 105 };
-
-        const Data = union(Type) {
-            no_op: void,
-
-            pub fn decode(buf: []const u8) Data {
-                _ = buf;
-                return @unionInit(Data, "no_op", {});
-            }
-        };
-
-        comptime {
-            std.debug.assert(@sizeOf(Data) != 0);
-        }
-
-        fn doTheTest() !void {
-            var data: Data = .{ .no_op = .{} };
-            _ = data;
-            var o = Data.decode(&[_]u8{});
-            try expectEqual(Type.no_op, o);
-        }
-    };
-
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
-
-test "union enum type gets a separate scope" {
-    const S = struct {
-        const U = union(enum) {
-            a: u8,
-            const foo = 1;
-        };
-
-        fn doTheTest() !void {
-            try expect(!@hasDecl(Tag(U), "foo"));
-        }
-    };
-
-    try S.doTheTest();
-}
-test "anytype union field: issue #9233" {
-    const Baz = union(enum) { bar: anytype };
-    _ = Baz;
-}
test/behavior/union_stage1.zig
@@ -0,0 +1,799 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
+const Tag = std.meta.Tag;
+
+const Value = union(enum) {
+    Int: u64,
+    Array: [9]u8,
+};
+
+const Agg = struct {
+    val1: Value,
+    val2: Value,
+};
+
+const v1 = Value{ .Int = 1234 };
+const v2 = Value{ .Array = [_]u8{3} ** 9 };
+
+const err = @as(anyerror!Agg, Agg{
+    .val1 = v1,
+    .val2 = v2,
+});
+
+const array = [_]Value{ v1, v2, v1, v2 };
+
+test "unions embedded in aggregate types" {
+    switch (array[1]) {
+        Value.Array => |arr| try expect(arr[4] == 3),
+        else => unreachable,
+    }
+    switch ((err catch unreachable).val1) {
+        Value.Int => |x| try expect(x == 1234),
+        else => unreachable,
+    }
+}
+
+const Foo = union {
+    float: f64,
+    int: i32,
+};
+
+test "basic unions" {
+    var foo = Foo{ .int = 1 };
+    try expect(foo.int == 1);
+    foo = Foo{ .float = 12.34 };
+    try expect(foo.float == 12.34);
+}
+
+test "comptime union field access" {
+    comptime {
+        var foo = Foo{ .int = 0 };
+        try expect(foo.int == 0);
+
+        foo = Foo{ .float = 42.42 };
+        try expect(foo.float == 42.42);
+    }
+}
+
+test "init union with runtime value" {
+    var foo: Foo = undefined;
+
+    setFloat(&foo, 12.34);
+    try expect(foo.float == 12.34);
+
+    setInt(&foo, 42);
+    try expect(foo.int == 42);
+}
+
+fn setFloat(foo: *Foo, x: f64) void {
+    foo.* = Foo{ .float = x };
+}
+
+fn setInt(foo: *Foo, x: i32) void {
+    foo.* = Foo{ .int = x };
+}
+
+const FooExtern = extern union {
+    float: f64,
+    int: i32,
+};
+
+test "basic extern unions" {
+    var foo = FooExtern{ .int = 1 };
+    try expect(foo.int == 1);
+    foo.float = 12.34;
+    try expect(foo.float == 12.34);
+}
+
+const Letter = enum { A, B, C };
+const Payload = union(Letter) {
+    A: i32,
+    B: f64,
+    C: bool,
+};
+
+test "union with specified enum tag" {
+    try doTest();
+    comptime try doTest();
+}
+
+fn doTest() error{TestUnexpectedResult}!void {
+    try expect((try bar(Payload{ .A = 1234 })) == -10);
+}
+
+fn bar(value: Payload) error{TestUnexpectedResult}!i32 {
+    try expect(@as(Letter, value) == Letter.A);
+    return switch (value) {
+        Payload.A => |x| return x - 1244,
+        Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,
+        Payload.C => |x| if (x) @as(i32, 30) else 31,
+    };
+}
+
+const MultipleChoice = union(enum(u32)) {
+    A = 20,
+    B = 40,
+    C = 60,
+    D = 1000,
+};
+test "simple union(enum(u32))" {
+    var x = MultipleChoice.C;
+    try expect(x == MultipleChoice.C);
+    try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60);
+}
+
+const MultipleChoice2 = union(enum(u32)) {
+    Unspecified1: i32,
+    A: f32 = 20,
+    Unspecified2: void,
+    B: bool = 40,
+    Unspecified3: i32,
+    C: i8 = 60,
+    Unspecified4: void,
+    D: void = 1000,
+    Unspecified5: i32,
+};
+
+test "union(enum(u32)) with specified and unspecified tag values" {
+    comptime try expect(Tag(Tag(MultipleChoice2)) == u32);
+    try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+    comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
+    try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60);
+    try expect(1123 == switch (x) {
+        MultipleChoice2.A => 1,
+        MultipleChoice2.B => 2,
+        MultipleChoice2.C => |v| @as(i32, 1000) + v,
+        MultipleChoice2.D => 4,
+        MultipleChoice2.Unspecified1 => 5,
+        MultipleChoice2.Unspecified2 => 6,
+        MultipleChoice2.Unspecified3 => 7,
+        MultipleChoice2.Unspecified4 => 8,
+        MultipleChoice2.Unspecified5 => 9,
+    });
+}
+
+const ExternPtrOrInt = extern union {
+    ptr: *u8,
+    int: u64,
+};
+test "extern union size" {
+    comptime try expect(@sizeOf(ExternPtrOrInt) == 8);
+}
+
+const PackedPtrOrInt = packed union {
+    ptr: *u8,
+    int: u64,
+};
+test "extern union size" {
+    comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
+}
+
+const ZeroBits = union {
+    OnlyField: void,
+};
+test "union with only 1 field which is void should be zero bits" {
+    comptime try expect(@sizeOf(ZeroBits) == 0);
+}
+
+const TheTag = enum { A, B, C };
+const TheUnion = union(TheTag) {
+    A: i32,
+    B: i32,
+    C: i32,
+};
+test "union field access gives the enum values" {
+    try expect(TheUnion.A == TheTag.A);
+    try expect(TheUnion.B == TheTag.B);
+    try expect(TheUnion.C == TheTag.C);
+}
+
+test "cast union to tag type of union" {
+    try testCastUnionToTag(TheUnion{ .B = 1234 });
+    comptime try testCastUnionToTag(TheUnion{ .B = 1234 });
+}
+
+fn testCastUnionToTag(x: TheUnion) !void {
+    try expect(@as(TheTag, x) == TheTag.B);
+}
+
+test "cast tag type of union to union" {
+    var x: Value2 = Letter2.B;
+    try expect(@as(Letter2, x) == Letter2.B);
+}
+const Letter2 = enum { A, B, C };
+const Value2 = union(Letter2) {
+    A: i32,
+    B,
+    C,
+};
+
+test "implicit cast union to its tag type" {
+    var x: Value2 = Letter2.B;
+    try expect(x == Letter2.B);
+    try giveMeLetterB(x);
+}
+fn giveMeLetterB(x: Letter2) !void {
+    try expect(x == Value2.B);
+}
+
+// TODO it looks like this test intended to test packed unions, but this is not a packed
+// union. go through git history and find out what happened.
+pub const PackThis = union(enum) {
+    Invalid: bool,
+    StringLiteral: u2,
+};
+
+test "constant packed union" {
+    try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});
+}
+
+fn testConstPackedUnion(expected_tokens: []const PackThis) !void {
+    try expect(expected_tokens[0].StringLiteral == 1);
+}
+
+test "switch on union with only 1 field" {
+    var r: PartialInst = undefined;
+    r = PartialInst.Compiled;
+    switch (r) {
+        PartialInst.Compiled => {
+            var z: PartialInstWithPayload = undefined;
+            z = PartialInstWithPayload{ .Compiled = 1234 };
+            switch (z) {
+                PartialInstWithPayload.Compiled => |x| {
+                    try expect(x == 1234);
+                    return;
+                },
+            }
+        },
+    }
+    unreachable;
+}
+
+const PartialInst = union(enum) {
+    Compiled,
+};
+
+const PartialInstWithPayload = union(enum) {
+    Compiled: i32,
+};
+
+test "access a member of tagged union with conflicting enum tag name" {
+    const Bar = union(enum) {
+        A: A,
+        B: B,
+
+        const A = u8;
+        const B = void;
+    };
+
+    comptime try expect(Bar.A == u8);
+}
+
+test "tagged union initialization with runtime void" {
+    try expect(testTaggedUnionInit({}));
+}
+
+const TaggedUnionWithAVoid = union(enum) {
+    A,
+    B: i32,
+};
+
+fn testTaggedUnionInit(x: anytype) bool {
+    const y = TaggedUnionWithAVoid{ .A = x };
+    return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A;
+}
+
+pub const UnionEnumNoPayloads = union(enum) { A, B };
+
+test "tagged union with no payloads" {
+    const a = UnionEnumNoPayloads{ .B = {} };
+    switch (a) {
+        Tag(UnionEnumNoPayloads).A => @panic("wrong"),
+        Tag(UnionEnumNoPayloads).B => {},
+    }
+}
+
+test "union with only 1 field casted to its enum type" {
+    const Literal = union(enum) {
+        Number: f64,
+        Bool: bool,
+    };
+
+    const Expr = union(enum) {
+        Literal: Literal,
+    };
+
+    var e = Expr{ .Literal = Literal{ .Bool = true } };
+    const ExprTag = Tag(Expr);
+    comptime try expect(Tag(ExprTag) == u0);
+    var t = @as(ExprTag, e);
+    try expect(t == Expr.Literal);
+}
+
+test "union with only 1 field casted to its enum type which has enum value specified" {
+    const Literal = union(enum) {
+        Number: f64,
+        Bool: bool,
+    };
+
+    const ExprTag = enum(comptime_int) {
+        Literal = 33,
+    };
+
+    const Expr = union(ExprTag) {
+        Literal: Literal,
+    };
+
+    var e = Expr{ .Literal = Literal{ .Bool = true } };
+    comptime try expect(Tag(ExprTag) == comptime_int);
+    var t = @as(ExprTag, e);
+    try expect(t == Expr.Literal);
+    try expect(@enumToInt(t) == 33);
+    comptime try expect(@enumToInt(t) == 33);
+}
+
+test "@enumToInt works on unions" {
+    const Bar = union(enum) {
+        A: bool,
+        B: u8,
+        C,
+    };
+
+    const a = Bar{ .A = true };
+    var b = Bar{ .B = undefined };
+    var c = Bar.C;
+    try expect(@enumToInt(a) == 0);
+    try expect(@enumToInt(b) == 1);
+    try expect(@enumToInt(c) == 2);
+}
+
+const Attribute = union(enum) {
+    A: bool,
+    B: u8,
+};
+
+fn setAttribute(attr: Attribute) void {
+    _ = attr;
+}
+
+fn Setter(attr: Attribute) type {
+    return struct {
+        fn set() void {
+            setAttribute(attr);
+        }
+    };
+}
+
+test "comptime union field value equality" {
+    const a0 = Setter(Attribute{ .A = false });
+    const a1 = Setter(Attribute{ .A = true });
+    const a2 = Setter(Attribute{ .A = false });
+
+    const b0 = Setter(Attribute{ .B = 5 });
+    const b1 = Setter(Attribute{ .B = 9 });
+    const b2 = Setter(Attribute{ .B = 5 });
+
+    try expect(a0 == a0);
+    try expect(a1 == a1);
+    try expect(a0 == a2);
+
+    try expect(b0 == b0);
+    try expect(b1 == b1);
+    try expect(b0 == b2);
+
+    try expect(a0 != b0);
+    try expect(a0 != a1);
+    try expect(b0 != b1);
+}
+
+test "return union init with void payload" {
+    const S = struct {
+        fn entry() !void {
+            try expect(func().state == State.one);
+        }
+        const Outer = union(enum) {
+            state: State,
+        };
+        const State = union(enum) {
+            one: void,
+            two: u32,
+        };
+        fn func() Outer {
+            return Outer{ .state = State{ .one = {} } };
+        }
+    };
+    try S.entry();
+    comptime try S.entry();
+}
+
+test "@unionInit can modify a union type" {
+    const UnionInitEnum = union(enum) {
+        Boolean: bool,
+        Byte: u8,
+    };
+
+    var value: UnionInitEnum = undefined;
+
+    value = @unionInit(UnionInitEnum, "Boolean", true);
+    try expect(value.Boolean == true);
+    value.Boolean = false;
+    try expect(value.Boolean == false);
+
+    value = @unionInit(UnionInitEnum, "Byte", 2);
+    try expect(value.Byte == 2);
+    value.Byte = 3;
+    try expect(value.Byte == 3);
+}
+
+test "@unionInit can modify a pointer value" {
+    const UnionInitEnum = union(enum) {
+        Boolean: bool,
+        Byte: u8,
+    };
+
+    var value: UnionInitEnum = undefined;
+    var value_ptr = &value;
+
+    value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
+    try expect(value.Boolean == true);
+
+    value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
+    try expect(value.Byte == 2);
+}
+
+test "union no tag with struct member" {
+    const Struct = struct {};
+    const Union = union {
+        s: Struct,
+        pub fn foo(self: *@This()) void {
+            _ = self;
+        }
+    };
+    var u = Union{ .s = Struct{} };
+    u.foo();
+}
+
+fn testComparison() !void {
+    var x = Payload{ .A = 42 };
+    try expect(x == .A);
+    try expect(x != .B);
+    try expect(x != .C);
+    try expect((x == .B) == false);
+    try expect((x == .C) == false);
+    try expect((x != .A) == false);
+}
+
+test "comparison between union and enum literal" {
+    try testComparison();
+    comptime try testComparison();
+}
+
+test "packed union generates correctly aligned LLVM type" {
+    const U = packed union {
+        f1: fn () error{TestUnexpectedResult}!void,
+        f2: u32,
+    };
+    var foo = [_]U{
+        U{ .f1 = doTest },
+        U{ .f2 = 0 },
+    };
+    try foo[0].f1();
+}
+
+test "union with one member defaults to u0 tag type" {
+    const U0 = union(enum) {
+        X: u32,
+    };
+    comptime try expect(Tag(Tag(U0)) == u0);
+}
+
+test "union with comptime_int tag" {
+    const Union = union(enum(comptime_int)) {
+        X: u32,
+        Y: u16,
+        Z: u8,
+    };
+    comptime try expect(Tag(Tag(Union)) == comptime_int);
+}
+
+test "extern union doesn't trigger field check at comptime" {
+    const U = extern union {
+        x: u32,
+        y: u8,
+    };
+
+    const x = U{ .x = 0x55AAAA55 };
+    comptime try expect(x.y == 0x55);
+}
+
+const Foo1 = union(enum) {
+    f: struct {
+        x: usize,
+    },
+};
+var glbl: Foo1 = undefined;
+
+test "global union with single field is correctly initialized" {
+    glbl = Foo1{
+        .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
+    };
+    try expect(glbl.f.x == 123);
+}
+
+pub const FooUnion = union(enum) {
+    U0: usize,
+    U1: u8,
+};
+
+var glbl_array: [2]FooUnion = undefined;
+
+test "initialize global array of union" {
+    glbl_array[1] = FooUnion{ .U1 = 2 };
+    glbl_array[0] = FooUnion{ .U0 = 1 };
+    try expect(glbl_array[0].U0 == 1);
+    try expect(glbl_array[1].U1 == 2);
+}
+
+test "anonymous union literal syntax" {
+    const S = struct {
+        const Number = union {
+            int: i32,
+            float: f64,
+        };
+
+        fn doTheTest() !void {
+            var i: Number = .{ .int = 42 };
+            var f = makeNumber();
+            try expect(i.int == 42);
+            try expect(f.float == 12.34);
+        }
+
+        fn makeNumber() Number {
+            return .{ .float = 12.34 };
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "update the tag value for zero-sized unions" {
+    const S = union(enum) {
+        U0: void,
+        U1: void,
+    };
+    var x = S{ .U0 = {} };
+    try expect(x == .U0);
+    x = S{ .U1 = {} };
+    try expect(x == .U1);
+}
+
+test "function call result coerces from tagged union to the tag" {
+    const S = struct {
+        const Arch = union(enum) {
+            One,
+            Two: usize,
+        };
+
+        const ArchTag = Tag(Arch);
+
+        fn doTheTest() !void {
+            var x: ArchTag = getArch1();
+            try expect(x == .One);
+
+            var y: ArchTag = getArch2();
+            try expect(y == .Two);
+        }
+
+        pub fn getArch1() Arch {
+            return .One;
+        }
+
+        pub fn getArch2() Arch {
+            return .{ .Two = 99 };
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "0-sized extern union definition" {
+    const U = extern union {
+        a: void,
+        const f = 1;
+    };
+
+    try expect(U.f == 1);
+}
+
+test "union initializer generates padding only if needed" {
+    const U = union(enum) {
+        A: u24,
+    };
+
+    var v = U{ .A = 532 };
+    try expect(v.A == 532);
+}
+
+test "runtime tag name with single field" {
+    const U = union(enum) {
+        A: i32,
+    };
+
+    var v = U{ .A = 42 };
+    try expect(std.mem.eql(u8, @tagName(v), "A"));
+}
+
+test "cast from anonymous struct to union" {
+    const S = struct {
+        const U = union(enum) {
+            A: u32,
+            B: []const u8,
+            C: void,
+        };
+        fn doTheTest() !void {
+            var y: u32 = 42;
+            const t0 = .{ .A = 123 };
+            const t1 = .{ .B = "foo" };
+            const t2 = .{ .C = {} };
+            const t3 = .{ .A = y };
+            const x0: U = t0;
+            var x1: U = t1;
+            const x2: U = t2;
+            var x3: U = t3;
+            try expect(x0.A == 123);
+            try expect(std.mem.eql(u8, x1.B, "foo"));
+            try expect(x2 == .C);
+            try expect(x3.A == y);
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "cast from pointer to anonymous struct to pointer to union" {
+    const S = struct {
+        const U = union(enum) {
+            A: u32,
+            B: []const u8,
+            C: void,
+        };
+        fn doTheTest() !void {
+            var y: u32 = 42;
+            const t0 = &.{ .A = 123 };
+            const t1 = &.{ .B = "foo" };
+            const t2 = &.{ .C = {} };
+            const t3 = &.{ .A = y };
+            const x0: *const U = t0;
+            var x1: *const U = t1;
+            const x2: *const U = t2;
+            var x3: *const U = t3;
+            try expect(x0.A == 123);
+            try expect(std.mem.eql(u8, x1.B, "foo"));
+            try expect(x2.* == .C);
+            try expect(x3.A == y);
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "method call on an empty union" {
+    const S = struct {
+        const MyUnion = union(MyUnionTag) {
+            pub const MyUnionTag = enum { X1, X2 };
+            X1: [0]u8,
+            X2: [0]u8,
+
+            pub fn useIt(self: *@This()) bool {
+                _ = self;
+                return true;
+            }
+        };
+
+        fn doTheTest() !void {
+            var u = MyUnion{ .X1 = [0]u8{} };
+            try expect(u.useIt());
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "switching on non exhaustive union" {
+    const S = struct {
+        const E = enum(u8) {
+            a,
+            b,
+            _,
+        };
+        const U = union(E) {
+            a: i32,
+            b: u32,
+        };
+        fn doTheTest() !void {
+            var a = U{ .a = 2 };
+            switch (a) {
+                .a => |val| try expect(val == 2),
+                .b => unreachable,
+            }
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "containers with single-field enums" {
+    const S = struct {
+        const A = union(enum) { f1 };
+        const B = union(enum) { f1: void };
+        const C = struct { a: A };
+        const D = struct { a: B };
+
+        fn doTheTest() !void {
+            var array1 = [1]A{A{ .f1 = {} }};
+            var array2 = [1]B{B{ .f1 = {} }};
+            try expect(array1[0] == .f1);
+            try expect(array2[0] == .f1);
+
+            var struct1 = C{ .a = A{ .f1 = {} } };
+            var struct2 = D{ .a = B{ .f1 = {} } };
+            try expect(struct1.a == .f1);
+            try expect(struct2.a == .f1);
+        }
+    };
+
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "@unionInit on union w/ tag but no fields" {
+    const S = struct {
+        const Type = enum(u8) { no_op = 105 };
+
+        const Data = union(Type) {
+            no_op: void,
+
+            pub fn decode(buf: []const u8) Data {
+                _ = buf;
+                return @unionInit(Data, "no_op", {});
+            }
+        };
+
+        comptime {
+            std.debug.assert(@sizeOf(Data) != 0);
+        }
+
+        fn doTheTest() !void {
+            var data: Data = .{ .no_op = .{} };
+            _ = data;
+            var o = Data.decode(&[_]u8{});
+            try expectEqual(Type.no_op, o);
+        }
+    };
+
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
+
+test "union enum type gets a separate scope" {
+    const S = struct {
+        const U = union(enum) {
+            a: u8,
+            const foo = 1;
+        };
+
+        fn doTheTest() !void {
+            try expect(!@hasDecl(Tag(U), "foo"));
+        }
+    };
+
+    try S.doTheTest();
+}
+test "anytype union field: issue #9233" {
+    const Baz = union(enum) { bar: anytype };
+    _ = Baz;
+}
test/behavior/widening.zig
@@ -17,3 +17,46 @@ test "implicit unsigned integer to signed integer" {
     var b: i16 = a;
     try expect(b == 250);
 }
+
+test "float widening" {
+    if (@import("builtin").zig_is_stage2) {
+        // This test is passing but it depends on compiler-rt symbols, which
+        // cannot yet be built with stage2 due to
+        // "TODO implement equality comparison between a union's tag value and an enum literal"
+        return error.SkipZigTest;
+    }
+    var a: f16 = 12.34;
+    var b: f32 = a;
+    var c: f64 = b;
+    var d: f128 = c;
+    try expect(a == b);
+    try expect(b == c);
+    try expect(c == d);
+}
+
+test "float widening f16 to f128" {
+    if (@import("builtin").zig_is_stage2) {
+        // This test is passing but it depends on compiler-rt symbols, which
+        // cannot yet be built with stage2 due to
+        // "TODO implement equality comparison between a union's tag value and an enum literal"
+        return error.SkipZigTest;
+    }
+    // TODO https://github.com/ziglang/zig/issues/3282
+    if (@import("builtin").stage2_arch == .aarch64) return error.SkipZigTest;
+    if (@import("builtin").stage2_arch == .powerpc64le) return error.SkipZigTest;
+
+    var x: f16 = 12.34;
+    var y: f128 = x;
+    try expect(x == y);
+}
+
+test "cast small unsigned to larger signed" {
+    try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200));
+    try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999));
+}
+fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
+    return x;
+}
+fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
+    return x;
+}
test/behavior/widening_stage1.zig
@@ -1,34 +0,0 @@
-const std = @import("std");
-const expect = std.testing.expect;
-const mem = std.mem;
-
-test "float widening" {
-    var a: f16 = 12.34;
-    var b: f32 = a;
-    var c: f64 = b;
-    var d: f128 = c;
-    try expect(a == b);
-    try expect(b == c);
-    try expect(c == d);
-}
-
-test "float widening f16 to f128" {
-    // TODO https://github.com/ziglang/zig/issues/3282
-    if (@import("builtin").stage2_arch == .aarch64) return error.SkipZigTest;
-    if (@import("builtin").stage2_arch == .powerpc64le) return error.SkipZigTest;
-
-    var x: f16 = 12.34;
-    var y: f128 = x;
-    try expect(x == y);
-}
-
-test "cast small unsigned to larger signed" {
-    try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200));
-    try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999));
-}
-fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
-    return x;
-}
-fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
-    return x;
-}
test/behavior.zig
@@ -13,6 +13,7 @@ test {
     _ = @import("behavior/atomics.zig");
     _ = @import("behavior/sizeof_and_typeof.zig");
     _ = @import("behavior/translate_c_macros.zig");
+    _ = @import("behavior/union.zig");
     _ = @import("behavior/widening.zig");
 
     if (builtin.zig_is_stage2) {
@@ -149,7 +150,7 @@ test {
         _ = @import("behavior/typename.zig");
         _ = @import("behavior/undefined.zig");
         _ = @import("behavior/underscore.zig");
-        _ = @import("behavior/union.zig");
+        _ = @import("behavior/union_stage1.zig");
         _ = @import("behavior/usingnamespace_stage1.zig");
         _ = @import("behavior/var_args.zig");
         _ = @import("behavior/vector.zig");
@@ -158,7 +159,6 @@ test {
             _ = @import("behavior/wasm.zig");
         }
         _ = @import("behavior/while.zig");
-        _ = @import("behavior/widening_stage1.zig");
         _ = @import("behavior/src.zig");
         _ = @import("behavior/translate_c_macros_stage1.zig");
     }