From aecebf38acc8835db21eeea7b53e4ee26ec739a8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 21 Sep 2021 22:33:00 -0700 Subject: [PATCH] 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. --- lib/std/special/compiler_rt.zig | 1184 ++++++++++--------- lib/std/special/compiler_rt/extendXfYf2.zig | 12 +- src/Air.zig | 10 +- src/AstGen.zig | 74 +- src/Liveness.zig | 3 +- src/Module.zig | 42 +- src/Sema.zig | 138 ++- src/Zir.zig | 14 +- src/codegen.zig | 15 +- src/codegen/c.zig | 10 +- src/codegen/llvm.zig | 36 +- src/codegen/llvm/bindings.zig | 16 + src/print_air.zig | 3 +- src/print_zir.zig | 12 + src/stage1/codegen.cpp | 1 + src/value.zig | 29 +- test/behavior.zig | 4 +- test/behavior/union.zig | 813 ------------- test/behavior/union_stage1.zig | 799 +++++++++++++ test/behavior/widening.zig | 43 + test/behavior/widening_stage1.zig | 34 - 21 files changed, 1734 insertions(+), 1558 deletions(-) create mode 100644 test/behavior/union_stage1.zig delete mode 100644 test/behavior/widening_stage1.zig diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index ed7f9d0c1c..2fb68f85dc 100644 --- a/lib/std/special/compiler_rt.zig +++ b/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; +const linkage = if (is_test) + std.builtin.GlobalLinkage.Internal +else + std.builtin.GlobalLinkage.Weak; + +const strong_linkage = if (is_test) + std.builtin.GlobalLinkage.Internal +else + std.builtin.GlobalLinkage.Strong; + 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 => {}, - } - - // __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 __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 ((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 (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 }); - } - - 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 }); - } - + if (!builtin.zig_is_stage2) { 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 }); + .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 => {}, } - 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 }); + + // __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, + }); + } + + 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 __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.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 (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 }); + } + + 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 __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 }); + } + } 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 { diff --git a/lib/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig index 5571bd9ed3..7afb6b1645 100644 --- a/lib/std/special/compiler_rt/extendXfYf2.zig +++ b/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); diff --git a/src/Air.zig b/src/Air.zig index ad95200001..c3181fac60 100644 --- a/src/Air.zig +++ b/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, diff --git a/src/AstGen.zig b/src/AstGen.zig index 176203d37f..6a533dff11 100644 --- a/src/AstGen.zig +++ b/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; + + 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_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; - } - 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; diff --git a/src/Liveness.zig b/src/Liveness.zig index 1d34da091d..dd0899e745 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -274,7 +274,8 @@ fn analyzeInst( .not, .bitcast, .load, - .floatcast, + .fpext, + .fptrunc, .intcast, .trunc, .optional_payload, diff --git a/src/Module.zig b/src/Module.zig index 88817efc26..70c90d9c01 100644 --- a/src/Module.zig +++ b/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; - const new_export = try mod.gpa.create(Export); - errdefer mod.gpa.destroy(new_export); + try mod.decl_exports.ensureUnusedCapacity(gpa, 1); + try mod.export_owners.ensureUnusedCapacity(gpa, 1); - const symbol_name = try mod.gpa.dupe(u8, borrowed_symbol_name); - errdefer mod.gpa.free(symbol_name); + const new_export = try gpa.create(Export); + errdefer gpa.destroy(new_export); + + 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. diff --git a/src/Sema.zig b/src/Sema.zig index 91d12b7b31..a0e3250e56 100644 --- a/src/Sema.zig +++ b/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) { - const result_val = try val.intToFloat(sema.arena, dest_type, target); + "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 => {}, } diff --git a/src/Zir.zig b/src/Zir.zig index 7f752bcced..d3b1678d97 100644 --- a/src/Zir.zig +++ b/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, diff --git a/src/codegen.zig b/src/codegen.zig index 54c1400211..06b520c9dd 100644 --- a/src/codegen.zig +++ b/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 }); } diff --git a/src/codegen/c.zig b/src/codegen/c.zig index c4e1d48062..a82f0e57f7 100644 --- a/src/codegen/c.zig +++ b/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) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3a977bc582..0d3bca2b03 100644 --- a/src/codegen/llvm.zig +++ b/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 { diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 039232426b..bf951fa67e 100644 --- a/src/codegen/llvm/bindings.zig +++ b/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) { diff --git a/src/print_air.zig b/src/print_air.zig index 3d13fa688f..a9ad993eb0 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -156,7 +156,8 @@ const Writer = struct { .not, .bitcast, .load, - .floatcast, + .fptrunc, + .fpext, .intcast, .trunc, .optional_payload, diff --git a/src/print_zir.zig b/src/print_zir.zig index 35b3da4479..4527b62262 100644 --- a/src/print_zir.zig +++ b/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); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 3b22101df9..1304dcc004 100644 --- a/src/stage1/codegen.cpp +++ b/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" diff --git a/src/value.zig b/src/value.zig index bdf5b9c37c..cb5d211b1e 100644 --- a/src/value.zig +++ b/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, } diff --git a/test/behavior.zig b/test/behavior.zig index f328db968e..7fbba99a8c 100644 --- a/test/behavior.zig +++ b/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"); } diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 323dd18f4d..14b5e374dd 100644 --- a/test/behavior/union.zig +++ b/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; -} diff --git a/test/behavior/union_stage1.zig b/test/behavior/union_stage1.zig new file mode 100644 index 0000000000..086bd981cd --- /dev/null +++ b/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; +} diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index efcbab9883..9c1694b368 100644 --- a/test/behavior/widening.zig +++ b/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; +} diff --git a/test/behavior/widening_stage1.zig b/test/behavior/widening_stage1.zig deleted file mode 100644 index 0cec3988cb..0000000000 --- a/test/behavior/widening_stage1.zig +++ /dev/null @@ -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; -}