diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f144cd68374ec7c0ec8c7ba7964cde06943d88a..14df4e9b568d8fb6c5b924f6cd4e3c9778dc5e21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,6 +358,8 @@ set(ZIG_STAGE2_SOURCES src/codegen/c/type/render_defs.zig src/codegen/llvm.zig src/codegen/llvm/bindings.zig + src/codegen/loongarch/abi.zig + src/codegen/s390x/abi.zig src/crash_report.zig src/dev.zig src/libs/freebsd.zig diff --git a/lib/compiler/aro/aro/Target.zig b/lib/compiler/aro/aro/Target.zig index 3a871504700f666b6e74ca464d37c0770568c43d..a0c9f3be3943810313dfcd94b94f6bea0794ff2d 100644 --- a/lib/compiler/aro/aro/Target.zig +++ b/lib/compiler/aro/aro/Target.zig @@ -1559,15 +1559,15 @@ pub fn ptrBitWidth(target: *const Target) u16 { } pub fn cCharSignedness(target: *const Target) std.builtin.Signedness { - return target.toZigTarget().cCharSignedness(); + return target.toZigTarget().cCharSignedness().?; } pub fn cTypeBitSize(target: *const Target, c_type: std.Target.CType) u16 { - return target.toZigTarget().cTypeBitSize(c_type); + return target.toZigTarget().cTypeBitSize(c_type).?; } pub fn cTypeAlignment(target: *const Target, c_type: std.Target.CType) u16 { - return target.toZigTarget().cTypeAlignment(c_type); + return target.toZigTarget().cTypeAlignment(c_type).?; } pub fn standardDynamicLinkerPath(target: *const Target) std.Target.DynamicLinker { diff --git a/lib/compiler/reduce.zig b/lib/compiler/reduce.zig index 04f0c03650031d0083cd84f89fa87bfa7b8aff09..398a44a9b4e1d9ec0670db4cd0d2878c37ff6c83 100644 --- a/lib/compiler/reduce.zig +++ b/lib/compiler/reduce.zig @@ -400,7 +400,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast { file_path, gpa, .limited(std.math.maxInt(u32)), - .fromByteUnits(1), + .@"1", 0, ) catch |err| { fatal("unable to open '{s}': {s}", .{ file_path, @errorName(err) }); diff --git a/lib/compiler/resinator/parse.zig b/lib/compiler/resinator/parse.zig index 445424429ea2249991661e99840331e2b936bd96..1f3b2f156ae15fb7fb548ffe37bce6f036079e19 100644 --- a/lib/compiler/resinator/parse.zig +++ b/lib/compiler/resinator/parse.zig @@ -1277,7 +1277,7 @@ pub const Parser = struct { }, else => unreachable, } - @compileError("unreachable"); + comptime unreachable; } pub const OptionalParamParser = struct { diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 62c09fe22800abc8aeb462dbd8c8beffe0ef7925..2827d32c496e12c3a2bf7c481b54afa50eb477fe 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -91,24 +91,23 @@ fn mainServer(init: std.process.Init.Minimal) !void { return std.process.exit(0); }, .query_test_metadata => { - testing.allocator_instance = .init(std.heap.page_allocator, .{}); - defer if (testing.allocator_instance.deinit() != 0) { - @panic("internal test runner memory leak"); - }; + var sa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{}); + defer if (sa.deinit() != 0) @panic("internal test runner memory leak"); + const gpa = sa.allocator(); var string_bytes: std.ArrayList(u8) = .empty; - defer string_bytes.deinit(testing.allocator); - try string_bytes.append(testing.allocator, 0); // Reserve 0 for null. + defer string_bytes.deinit(gpa); + try string_bytes.append(gpa, 0); // Reserve 0 for null. const test_fns = builtin.test_functions; - const names = try testing.allocator.alloc(u32, test_fns.len); - defer testing.allocator.free(names); - const expected_panic_msgs = try testing.allocator.alloc(u32, test_fns.len); - defer testing.allocator.free(expected_panic_msgs); + const names = try gpa.alloc(u32, test_fns.len); + defer gpa.free(names); + const expected_panic_msgs = try gpa.alloc(u32, test_fns.len); + defer gpa.free(expected_panic_msgs); for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| { name.* = @intCast(string_bytes.items.len); - try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1); + try string_bytes.ensureUnusedCapacity(gpa, test_fn.name.len + 1); string_bytes.appendSliceAssumeCapacity(test_fn.name); string_bytes.appendAssumeCapacity(0); expected_panic_msg.* = 0; @@ -377,6 +376,7 @@ pub fn mainSimple() anyerror!void { else => false, }; + testing.allocator_instance = .init(std.heap.page_allocator, .{}); testing.io_instance = .init(testing.allocator, .{}); var passed: u64 = 0; diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index f042d0076e62740c50d61b4e28b8b3ddb07012f3..5ff6e659d56f0797225b7661aa076cb41f715a42 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -1,4 +1,5 @@ const builtin = @import("builtin"); +const compiler_rt = @This(); const ofmt_c = builtin.object_format == .c; const native_endian = builtin.cpu.arch.endian(); @@ -84,144 +85,17 @@ comptime { // Float routines // conversion _ = @import("compiler_rt/extendf.zig"); - _ = @import("compiler_rt/extendhfsf2.zig"); - _ = @import("compiler_rt/extendhfdf2.zig"); - _ = @import("compiler_rt/extendhftf2.zig"); - _ = @import("compiler_rt/extendhfxf2.zig"); - _ = @import("compiler_rt/extendsfdf2.zig"); - _ = @import("compiler_rt/extendsftf2.zig"); - _ = @import("compiler_rt/extendsfxf2.zig"); - _ = @import("compiler_rt/extenddftf2.zig"); - _ = @import("compiler_rt/extenddfxf2.zig"); - _ = @import("compiler_rt/extendxftf2.zig"); - _ = @import("compiler_rt/truncf.zig"); - _ = @import("compiler_rt/truncsfhf2.zig"); - _ = @import("compiler_rt/truncdfhf2.zig"); - _ = @import("compiler_rt/truncdfsf2.zig"); - _ = @import("compiler_rt/truncxfhf2.zig"); - _ = @import("compiler_rt/truncxfsf2.zig"); - _ = @import("compiler_rt/truncxfdf2.zig"); - _ = @import("compiler_rt/trunctfhf2.zig"); - _ = @import("compiler_rt/trunctfsf2.zig"); - _ = @import("compiler_rt/trunctfdf2.zig"); - _ = @import("compiler_rt/trunctfxf2.zig"); - _ = @import("compiler_rt/int_from_float.zig"); - _ = @import("compiler_rt/fixhfei.zig"); - _ = @import("compiler_rt/fixsfsi.zig"); - _ = @import("compiler_rt/fixsfdi.zig"); - _ = @import("compiler_rt/fixsfti.zig"); - _ = @import("compiler_rt/fixsfei.zig"); - _ = @import("compiler_rt/fixdfsi.zig"); - _ = @import("compiler_rt/fixdfdi.zig"); - _ = @import("compiler_rt/fixdfti.zig"); - _ = @import("compiler_rt/fixdfei.zig"); - _ = @import("compiler_rt/fixtfsi.zig"); - _ = @import("compiler_rt/fixtfdi.zig"); - _ = @import("compiler_rt/fixtfti.zig"); - _ = @import("compiler_rt/fixtfei.zig"); - _ = @import("compiler_rt/fixxfsi.zig"); - _ = @import("compiler_rt/fixxfdi.zig"); - _ = @import("compiler_rt/fixxfei.zig"); - - _ = @import("compiler_rt/fixunshfsi.zig"); - _ = @import("compiler_rt/fixunshfdi.zig"); - _ = @import("compiler_rt/fixunshfti.zig"); - _ = @import("compiler_rt/fixunshfei.zig"); - _ = @import("compiler_rt/fixunssfsi.zig"); - _ = @import("compiler_rt/fixunssfdi.zig"); - _ = @import("compiler_rt/fixunssfti.zig"); - _ = @import("compiler_rt/fixunssfei.zig"); - _ = @import("compiler_rt/fixunsdfsi.zig"); - _ = @import("compiler_rt/fixunsdfdi.zig"); - _ = @import("compiler_rt/fixunsdfti.zig"); - _ = @import("compiler_rt/fixunsdfei.zig"); - _ = @import("compiler_rt/fixunstfsi.zig"); - _ = @import("compiler_rt/fixunstfdi.zig"); - _ = @import("compiler_rt/fixunstfti.zig"); - _ = @import("compiler_rt/fixunstfei.zig"); - _ = @import("compiler_rt/fixunsxfsi.zig"); - _ = @import("compiler_rt/fixunsxfdi.zig"); - _ = @import("compiler_rt/fixunsxfti.zig"); - _ = @import("compiler_rt/fixunsxfei.zig"); - _ = @import("compiler_rt/float_from_int.zig"); - _ = @import("compiler_rt/floatsihf.zig"); - _ = @import("compiler_rt/floatsisf.zig"); - _ = @import("compiler_rt/floatsidf.zig"); - _ = @import("compiler_rt/floatsitf.zig"); - _ = @import("compiler_rt/floatsixf.zig"); - _ = @import("compiler_rt/floatdihf.zig"); - _ = @import("compiler_rt/floatdisf.zig"); - _ = @import("compiler_rt/floatdidf.zig"); - _ = @import("compiler_rt/floatditf.zig"); - _ = @import("compiler_rt/floatdixf.zig"); - _ = @import("compiler_rt/floattihf.zig"); - _ = @import("compiler_rt/floattisf.zig"); - _ = @import("compiler_rt/floattidf.zig"); - _ = @import("compiler_rt/floattitf.zig"); - _ = @import("compiler_rt/floattixf.zig"); - _ = @import("compiler_rt/floateihf.zig"); - _ = @import("compiler_rt/floateisf.zig"); - _ = @import("compiler_rt/floateidf.zig"); - _ = @import("compiler_rt/floateitf.zig"); - _ = @import("compiler_rt/floateixf.zig"); - _ = @import("compiler_rt/floatunsihf.zig"); - _ = @import("compiler_rt/floatunsisf.zig"); - _ = @import("compiler_rt/floatunsidf.zig"); - _ = @import("compiler_rt/floatunsitf.zig"); - _ = @import("compiler_rt/floatunsixf.zig"); - _ = @import("compiler_rt/floatundihf.zig"); - _ = @import("compiler_rt/floatundisf.zig"); - _ = @import("compiler_rt/floatundidf.zig"); - _ = @import("compiler_rt/floatunditf.zig"); - _ = @import("compiler_rt/floatundixf.zig"); - _ = @import("compiler_rt/floatuntihf.zig"); - _ = @import("compiler_rt/floatuntisf.zig"); - _ = @import("compiler_rt/floatuntidf.zig"); - _ = @import("compiler_rt/floatuntitf.zig"); - _ = @import("compiler_rt/floatuntixf.zig"); - _ = @import("compiler_rt/floatuneihf.zig"); - _ = @import("compiler_rt/floatuneisf.zig"); - _ = @import("compiler_rt/floatuneidf.zig"); - _ = @import("compiler_rt/floatuneitf.zig"); - _ = @import("compiler_rt/floatuneixf.zig"); // comparison _ = @import("compiler_rt/comparef.zig"); - _ = @import("compiler_rt/cmpdf2.zig"); - _ = @import("compiler_rt/cmptf2.zig"); - _ = @import("compiler_rt/cmpxf2.zig"); - _ = @import("compiler_rt/unorddf2.zig"); - _ = @import("compiler_rt/gehf2.zig"); - _ = @import("compiler_rt/gesf2.zig"); - _ = @import("compiler_rt/gedf2.zig"); - _ = @import("compiler_rt/gexf2.zig"); - _ = @import("compiler_rt/getf2.zig"); // arithmetic _ = @import("compiler_rt/addf3.zig"); - _ = @import("compiler_rt/addhf3.zig"); - _ = @import("compiler_rt/addsf3.zig"); - _ = @import("compiler_rt/adddf3.zig"); - _ = @import("compiler_rt/addtf3.zig"); - _ = @import("compiler_rt/addxf3.zig"); - - _ = @import("compiler_rt/subhf3.zig"); - _ = @import("compiler_rt/subsf3.zig"); - _ = @import("compiler_rt/subdf3.zig"); - _ = @import("compiler_rt/subtf3.zig"); - _ = @import("compiler_rt/subxf3.zig"); - _ = @import("compiler_rt/mulf3.zig"); - _ = @import("compiler_rt/mulhf3.zig"); - _ = @import("compiler_rt/mulsf3.zig"); - _ = @import("compiler_rt/muldf3.zig"); - _ = @import("compiler_rt/multf3.zig"); - _ = @import("compiler_rt/mulxf3.zig"); - _ = @import("compiler_rt/divhf3.zig"); _ = @import("compiler_rt/divsf3.zig"); _ = @import("compiler_rt/divdf3.zig"); _ = @import("compiler_rt/divxf3.zig"); @@ -235,25 +109,17 @@ comptime { symbol(&__negsf2, "__negsf2"); symbol(&__negdf2, "__negdf2"); } - if (want_ppc_abi) symbol(&__negtf2, "__negkf2"); - symbol(&__negtf2, "__negtf2"); + if (want_ppc_abi) { + symbol(&__negtf2, "__negkf2"); + } else { + symbol(&__negtf2, "__negtf2"); + } symbol(&__negxf2, "__negxf2"); // other _ = @import("compiler_rt/powiXf2.zig"); _ = @import("compiler_rt/mulc3.zig"); - _ = @import("compiler_rt/mulhc3.zig"); - _ = @import("compiler_rt/mulsc3.zig"); - _ = @import("compiler_rt/muldc3.zig"); - _ = @import("compiler_rt/mulxc3.zig"); - _ = @import("compiler_rt/multc3.zig"); - _ = @import("compiler_rt/divc3.zig"); - _ = @import("compiler_rt/divhc3.zig"); - _ = @import("compiler_rt/divsc3.zig"); - _ = @import("compiler_rt/divdc3.zig"); - _ = @import("compiler_rt/divxc3.zig"); - _ = @import("compiler_rt/divtc3.zig"); // Math routines. Alphabetically sorted. _ = @import("compiler_rt/cos.zig"); @@ -279,7 +145,7 @@ comptime { _ = @import("compiler_rt/divmodei4.zig"); _ = @import("compiler_rt/udivmodei4.zig"); - _ = @import("compiler_rt/limb64.zig"); + if (builtin.cpu.arch.isWasm()) _ = @import("compiler_rt/limb64.zig"); // extra _ = @import("compiler_rt/os_version_check.zig"); @@ -290,7 +156,7 @@ comptime { _ = @import("compiler_rt/clear_cache.zig"); _ = @import("compiler_rt/hexagon.zig"); - if (@import("builtin").object_format != .c) { + if (builtin.object_format != .c) { if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); _ = @import("compiler_rt/stack_probe.zig"); @@ -366,10 +232,7 @@ pub const want_aeabi = switch (builtin.abi) { .gnueabihf, .android, .androideabi, - => switch (builtin.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => true, - else => false, - }, + => builtin.cpu.arch.isArm(), else => false, }; @@ -443,17 +306,106 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) { pub const want_sparc64_abi = builtin.cpu.arch == .sparc64; pub const want_sparc32_abi = builtin.cpu.arch == .sparc; -pub fn F16T(comptime OtherType: type) type { - return switch (builtin.cpu.arch) { - .x86, .x86_64 => if (builtin.target.os.tag.isDarwin()) switch (OtherType) { - // Starting with LLVM 16, Darwin uses different abi for f16 - // depending on the type of the other return/argument..??? - f32, f64 => u16, - f80, f128 => f16, - else => unreachable, - } else f16, - else => f16, +/// For operations converting between `f16` and another floating point type. +pub fn f16Conv(comptime OtherType: type) type { + switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { + .hard => {}, + .soft => return softFloatAbi(f16), + } + if (builtin.cpu.arch.isX86() and builtin.os.tag.isDarwin()) switch (OtherType) { + else => unreachable, + // Starting with LLVM 16, Darwin uses different abi for f16 + // depending on the type of the other return/argument..??? + f32, f64 => return softFloatAbi(f16), + f80, f128 => {}, }; + return hardFloatAbi(f16); +} +pub const @"f16" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { + .hard => hardFloatAbi(f16), + .soft => softFloatAbi(f16), +}; +pub const @"f32" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 32)) { + .hard => hardFloatAbi(f32), + .soft => softFloatAbi(f32), +}; +pub const @"f64" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 64)) { + .hard => hardFloatAbi(f64), + .soft => softFloatAbi(f64), +}; +pub const @"f80" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 80)) { + .hard => hardFloatAbi(f80), + .soft => struct { + pub const Abi = extern struct { mantissa: u64, exponent: u16 }; + const Repr = packed struct { mantissa: u64, exponent: u16 }; + pub inline fn toAbi(raw: f80) Abi { + const repr: Repr = @bitCast(raw); + return .{ .mantissa = repr.mantissa, .exponent = repr.exponent }; + } + pub inline fn fromAbi(abi: Abi) f80 { + const repr: Repr = .{ .mantissa = abi.mantissa, .exponent = abi.exponent }; + return @bitCast(repr); + } + pub const complex = complexAbi(f80, @This()); + }, +}; +pub const @"f128" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 128)) { + .hard => hardFloatAbi(f128), + .soft => struct { + pub const Abi = switch (builtin.cpu.arch.endian()) { + .big => extern struct { hi: u64, lo: u64 }, + .little => extern struct { lo: u64, hi: u64 }, + }; + const Repr = packed struct { lo: u64, hi: u64 }; + pub inline fn toAbi(raw: f128) Abi { + const repr: Repr = @bitCast(raw); + return .{ .lo = repr.lo, .hi = repr.hi }; + } + pub inline fn fromAbi(abi: Abi) f128 { + const repr: Repr = .{ .lo = abi.lo, .hi = abi.hi }; + return @bitCast(repr); + } + pub const complex = complexAbi(f128, @This()); + }, +}; +fn hardFloatAbi(comptime Float: type) type { + return struct { + pub const Abi = Float; + pub inline fn toAbi(raw: Float) Abi { + return raw; + } + pub inline fn fromAbi(abi: Abi) Float { + return abi; + } + pub const complex = complexAbi(Float, @This()); + }; +} +fn softFloatAbi(comptime Float: type) type { + return struct { + pub const Abi = @Int(.unsigned, @bitSizeOf(Float)); + pub inline fn toAbi(raw: Float) Abi { + return @bitCast(raw); + } + pub inline fn fromAbi(abi: Abi) Float { + return @bitCast(abi); + } + pub const complex = complexAbi(Float, @This()); + }; +} +fn complexAbi(comptime Float: type, comptime float: type) type { + return struct { + pub const Abi = extern struct { real: float.Abi, imag: float.Abi }; + pub inline fn toAbi(raw: Complex(Float)) Abi { + return .{ .real = float.toAbi(raw.real), .imag = float.toAbi(raw.imag) }; + } + pub inline fn fromAbi(abi: Abi) Complex(Float) { + return .{ .real = float.fromAbi(abi.real), .imag = float.fromAbi(abi.imag) }; + } + }; +} + +pub fn Complex(comptime Float: type) type { + return struct { real: Float, imag: Float }; } pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { @@ -588,34 +540,34 @@ pub inline fn fneg(a: anytype) @TypeOf(a) { return @bitCast(negated); } -fn __negxf2(a: f80) callconv(.c) f80 { - return fneg(a); +fn __neghf2(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fneg(compiler_rt.f16.fromAbi(a))); } -fn __neghf2(a: f16) callconv(.c) f16 { - return fneg(a); +fn __negsf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fneg(compiler_rt.f32.fromAbi(a))); } -fn __negdf2(a: f64) callconv(.c) f64 { - return fneg(a); +fn __negdf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fneg(compiler_rt.f64.fromAbi(a))); } -fn __aeabi_dneg(a: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return fneg(a); +fn __negxf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fneg(compiler_rt.f80.fromAbi(a))); } -fn __negtf2(a: f128) callconv(.c) f128 { - return fneg(a); -} - -fn __negsf2(a: f32) callconv(.c) f32 { - return fneg(a); +fn __negtf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fneg(compiler_rt.f128.fromAbi(a))); } fn __aeabi_fneg(a: f32) callconv(.{ .arm_aapcs = .{} }) f32 { return fneg(a); } +fn __aeabi_dneg(a: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return fneg(a); +} + /// Allows to access underlying bits as two equally sized lower and higher /// signed or unsigned integers. pub fn HalveInt(comptime T: type, comptime signed_half: bool) type { diff --git a/lib/compiler_rt/absv.zig b/lib/compiler_rt/absv.zig index 8910a4a6b9417bd099065db02f1535ace9968ee0..4621835dd6f6abd9cdb37a53231e88139556eb9a 100644 --- a/lib/compiler_rt/absv.zig +++ b/lib/compiler_rt/absv.zig @@ -14,8 +14,7 @@ pub inline fn absv(comptime ST: type, a: ST) ST { const sign: ST = a >> N - 1; x +%= sign; x ^= sign; - if (x < 0) - @panic("compiler_rt absv: overflow"); + if (x < 0) @panic("integer overflow"); return x; } diff --git a/lib/compiler_rt/absvdi2.zig b/lib/compiler_rt/absvdi2.zig index 408d70ad167d29c7895e6145e7635da95ec62a82..598629ebfc689258a055110aa976cf0d3b56226a 100644 --- a/lib/compiler_rt/absvdi2.zig +++ b/lib/compiler_rt/absvdi2.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const absv = @import("./absv.zig").absv; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvdi2, "__absvdi2"); diff --git a/lib/compiler_rt/absvsi2.zig b/lib/compiler_rt/absvsi2.zig index 538d7f7f0155f98cf997b711514145ae77da5c2a..e01627090082800cd53ee4b614f3a68d9480c214 100644 --- a/lib/compiler_rt/absvsi2.zig +++ b/lib/compiler_rt/absvsi2.zig @@ -1,6 +1,6 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; -const absv = @import("./absv.zig").absv; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvsi2, "__absvsi2"); diff --git a/lib/compiler_rt/absvti2.zig b/lib/compiler_rt/absvti2.zig index ab367d2b78ae2f0a813d011ec74dc532d103303f..008060504e318f7d9979a43d4d53ac34a8d38c76 100644 --- a/lib/compiler_rt/absvti2.zig +++ b/lib/compiler_rt/absvti2.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const absv = @import("./absv.zig").absv; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvti2, "__absvti2"); diff --git a/lib/compiler_rt/adddf3.zig b/lib/compiler_rt/adddf3.zig deleted file mode 100644 index 7b6f252da2c7f697b23b8e9e9fd13d34cc99bc80..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/adddf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dadd, "__aeabi_dadd"); - } else { - symbol(&__adddf3, "__adddf3"); - } -} - -fn __adddf3(a: f64, b: f64) callconv(.c) f64 { - return addf3(f64, a, b); -} - -fn __aeabi_dadd(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return addf3(f64, a, b); -} diff --git a/lib/compiler_rt/addf3.zig b/lib/compiler_rt/addf3.zig index 1e68c82f0fbcf3a4a28d4d9c0d877b997496d7a2..189f7afd6d02c78bdb63de8e38ca7731c96684d4 100644 --- a/lib/compiler_rt/addf3.zig +++ b/lib/compiler_rt/addf3.zig @@ -1,12 +1,143 @@ const std = @import("std"); const math = std.math; const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; +comptime { + symbol(&__addhf3, "__addhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fadd, "__aeabi_fadd"); + symbol(&__aeabi_dadd, "__aeabi_dadd"); + } else { + symbol(&__addsf3, "__addsf3"); + symbol(&__adddf3, "__adddf3"); + } + symbol(&__addxf3, "__addxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__addtf3, "__addkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_add, "_Qp_add"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__addtf3, "_Q_add"); + } else { + symbol(&__addtf3, "__addtf3"); + } +} + +fn __addhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(add_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn add_f16(a: f16, b: f16) f16 { + return addf3(f16, a, b); +} + +fn __addsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(add_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fadd(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return add_f32(a, b); +} +pub fn add_f32(a: f32, b: f32) f32 { + return addf3(f32, a, b); +} + +fn __adddf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(add_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dadd(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return add_f64(a, b); +} +pub fn add_f64(a: f64, b: f64) f64 { + return addf3(f64, a, b); +} + +fn __addxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(add_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn add_f80(a: f80, b: f80) f80 { + return addf3(f80, a, b); +} + +fn __addtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(add_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.c) void { + c.* = add_f128(a.*, b.*); +} +pub fn add_f128(a: f128, b: f128) f128 { + return addf3(f128, a, b); +} + +comptime { + symbol(&__subhf3, "__subhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fsub, "__aeabi_fsub"); + symbol(&__aeabi_dsub, "__aeabi_dsub"); + } else { + symbol(&__subsf3, "__subsf3"); + symbol(&__subdf3, "__subdf3"); + } + symbol(&__subxf3, "__subxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__subtf3, "__subkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_sub, "_Qp_sub"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__subtf3, "_Q_sub"); + } else { + symbol(&__subtf3, "__subtf3"); + } +} + +fn __subhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sub_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn sub_f16(a: f16, b: f16) f16 { + return add_f16(a, compiler_rt.fneg(b)); +} + +fn __subsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sub_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fsub(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return sub_f32(a, b); +} +pub fn sub_f32(a: f32, b: f32) f32 { + return add_f32(a, compiler_rt.fneg(b)); +} + +fn __subdf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sub_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dsub(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return sub_f64(a, b); +} +pub fn sub_f64(a: f64, b: f64) f64 { + return add_f64(a, compiler_rt.fneg(b)); +} + +fn __subxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sub_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn sub_f80(a: f80, b: f80) f80 { + return add_f80(a, compiler_rt.fneg(b)); +} + +fn __subtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sub_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { + c.* = sub_f128(a.*, b.*); +} +pub fn sub_f128(a: f128, b: f128) f128 { + return add_f128(a, compiler_rt.fneg(b)); +} + /// Ported from: /// /// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc -pub inline fn addf3(comptime T: type, a: T, b: T) T { +inline fn addf3(comptime T: type, a: T, b: T) T { const bits = @typeInfo(T).float.bits; const Z = @Int(.unsigned, bits); diff --git a/lib/compiler_rt/addf3_test.zig b/lib/compiler_rt/addf3_test.zig index 1e9bfa1bbf5403cee4cb6fc839478782714eca5b..ffa3a48086a47e9617145c0d33e049b221303ec5 100644 --- a/lib/compiler_rt/addf3_test.zig +++ b/lib/compiler_rt/addf3_test.zig @@ -8,12 +8,13 @@ const builtin = @import("builtin"); const math = std.math; const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64); -const __addtf3 = @import("addtf3.zig").__addtf3; -const __addxf3 = @import("addxf3.zig").__addxf3; -const __subtf3 = @import("subtf3.zig").__subtf3; +const impl = @import("addf3.zig"); +const add_f128 = impl.add_f128; +const add_f80 = impl.add_f80; +const sub_f128 = impl.sub_f128; fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __addtf3(a, b); + const x = add_f128(a, b); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -52,7 +53,7 @@ test "addtf3" { } fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __subtf3(a, b); + const x = sub_f128(a, b); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -91,7 +92,7 @@ test "subtf3" { const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))); fn test__addxf3(a: f80, b: f80, expected: u80) !void { - const x = __addxf3(a, b); + const x = add_f80(a, b); const rep: u80 = @bitCast(x); if (rep == expected) diff --git a/lib/compiler_rt/addhf3.zig b/lib/compiler_rt/addhf3.zig deleted file mode 100644 index bd13f48cac5f1ebeda2f019b1252d6a6967aa964..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__addhf3, "__addhf3"); -} - -fn __addhf3(a: f16, b: f16) callconv(.c) f16 { - return addf3(f16, a, b); -} diff --git a/lib/compiler_rt/addsf3.zig b/lib/compiler_rt/addsf3.zig deleted file mode 100644 index 4878fb704d1769469fb0a9155c930f0e24e0cabc..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addsf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fadd, "__aeabi_fadd"); - } else { - symbol(&__addsf3, "__addsf3"); - } -} - -fn __addsf3(a: f32, b: f32) callconv(.c) f32 { - return addf3(f32, a, b); -} - -fn __aeabi_fadd(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return addf3(f32, a, b); -} diff --git a/lib/compiler_rt/addtf3.zig b/lib/compiler_rt/addtf3.zig deleted file mode 100644 index 3097027f482ed73deee604acfcd7be877192d1fc..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addtf3.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__addtf3, "__addkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_add, "_Qp_add"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__addtf3, "_Q_add"); - } - symbol(&__addtf3, "__addtf3"); -} - -pub fn __addtf3(a: f128, b: f128) callconv(.c) f128 { - return addf3(f128, a, b); -} - -fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.c) void { - c.* = addf3(f128, a.*, b.*); -} diff --git a/lib/compiler_rt/addvdi3.zig b/lib/compiler_rt/addvdi3.zig index a5cde2494acba14282409395aa47ce9660faa0ff..063c2bcd44f16ea3dcd14fb427b24835830190bd 100644 --- a/lib/compiler_rt/addvdi3.zig +++ b/lib/compiler_rt/addvdi3.zig @@ -1,4 +1,5 @@ -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; const testing = @import("std").testing; comptime { @@ -9,7 +10,7 @@ pub fn __addvdi3(a: i64, b: i64) callconv(.c) i64 { const sum = a +% b; // Overflow occurred iff both operands have the same sign, and the sign of the sum does // not match it. In other words, iff the sum sign is not the sign of either operand. - if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); + if (((sum ^ a) & (sum ^ b)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/addvsi3.zig b/lib/compiler_rt/addvsi3.zig index c35b22e8dfd73703480c89f4a5d305fa5b8ec9fd..f180f680c52e8ddc4a991838714eff4647cb57ba 100644 --- a/lib/compiler_rt/addvsi3.zig +++ b/lib/compiler_rt/addvsi3.zig @@ -10,7 +10,7 @@ pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { const sum = a +% b; // Overflow occurred iff both operands have the same sign, and the sign of the sum does // not match it. In other words, iff the sum sign is not the sign of either operand. - if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); + if (((sum ^ a) & (sum ^ b)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/addxf3.zig b/lib/compiler_rt/addxf3.zig deleted file mode 100644 index f57708c98553874b47b62591b339e49b22ecedbd..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addxf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__addxf3, "__addxf3"); -} - -pub fn __addxf3(a: f80, b: f80) callconv(.c) f80 { - return addf3(f80, a, b); -} diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig index f2c744c730b8c20501af60bf51fa78d57cb7cbc3..83b978a11ca2fad3dc2e4f8483556751c2f6e3d1 100644 --- a/lib/compiler_rt/atomics.zig +++ b/lib/compiler_rt/atomics.zig @@ -5,7 +5,7 @@ const arch = cpu.arch; const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; // This parameter is true iff the target architecture supports the bare minimum // to implement the atomic load/store intrinsics. diff --git a/lib/compiler_rt/aulldiv.zig b/lib/compiler_rt/aulldiv.zig index 4ed92f39eefde1b941634b5b72eac8d1e41ba0d2..3e002379220fa5e957f2d2a728435a2a11972415 100644 --- a/lib/compiler_rt/aulldiv.zig +++ b/lib/compiler_rt/aulldiv.zig @@ -1,7 +1,7 @@ const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { if (compiler_rt.want_windows_x86_msvc_abi) { diff --git a/lib/compiler_rt/cmpdf2.zig b/lib/compiler_rt/cmpdf2.zig deleted file mode 100644 index e55972efbd00da3c3b215e722ba2277557a37525..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmpdf2.zig +++ /dev/null @@ -1,67 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpeq, "__aeabi_dcmpeq"); - symbol(&__aeabi_dcmplt, "__aeabi_dcmplt"); - symbol(&__aeabi_dcmple, "__aeabi_dcmple"); - } else { - symbol(&__eqdf2, "__eqdf2"); - symbol(&__nedf2, "__nedf2"); - symbol(&__ledf2, "__ledf2"); - symbol(&__cmpdf2, "__cmpdf2"); - symbol(&__ltdf2, "__ltdf2"); - } -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__ledf2`, `__eqdf2`, `__nedf2`, `__cmpdf2`, -/// and `__ltdf2`. -fn __cmpdf2(a: f64, b: f64) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f64, comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -pub fn __ledf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined -/// to have the same return value. -pub fn __eqdf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined -/// to have the same return value. -pub fn __nedf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -pub fn __ltdf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) == .Equal); -} - -fn __aeabi_dcmplt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) == .Less); -} - -fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater); -} diff --git a/lib/compiler_rt/cmptf2.zig b/lib/compiler_rt/cmptf2.zig deleted file mode 100644 index 89418fb320b5b8ea3d2f972cf05dde162eccc7c0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmptf2.zig +++ /dev/null @@ -1,146 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__eqtf2, "__eqkf2"); - symbol(&__netf2, "__nekf2"); - symbol(&__lttf2, "__ltkf2"); - symbol(&__letf2, "__lekf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_cmp, "_Qp_cmp"); - symbol(&_Qp_feq, "_Qp_feq"); - symbol(&_Qp_fne, "_Qp_fne"); - symbol(&_Qp_flt, "_Qp_flt"); - symbol(&_Qp_fle, "_Qp_fle"); - symbol(&_Qp_fgt, "_Qp_fgt"); - symbol(&_Qp_fge, "_Qp_fge"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&_Q_cmp, "_Q_cmp"); - symbol(&_Q_feq, "_Q_feq"); - symbol(&_Q_fne, "_Q_fne"); - symbol(&_Q_flt, "_Q_flt"); - symbol(&_Q_fle, "_Q_fle"); - symbol(&_Q_fgt, "_Q_fgt"); - symbol(&_Q_fge, "_Q_fge"); - } - symbol(&__eqtf2, "__eqtf2"); - symbol(&__netf2, "__netf2"); - symbol(&__letf2, "__letf2"); - symbol(&__cmptf2, "__cmptf2"); - symbol(&__lttf2, "__lttf2"); -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__letf2`, `__eqtf2`, `__netf2`, `__cmptf2`, -/// and `__lttf2`. -fn __cmptf2(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __letf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined -/// to have the same return value. -fn __eqtf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined -/// to have the same return value. -fn __netf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __lttf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -const SparcFCMP = enum(i32) { - Equal = 0, - Less = 1, - Greater = 2, - Unordered = 3, -}; - -fn _Qp_cmp(a: *const f128, b: *const f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, SparcFCMP, a.*, b.*)); -} - -fn _Qp_feq(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Equal; -} - -fn _Qp_fne(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) != .Equal; -} - -fn _Qp_flt(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Less; -} - -fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Greater; -} - -fn _Qp_fge(a: *const f128, b: *const f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b))))) { - .Equal, .Greater => true, - .Less, .Unordered => false, - }; -} - -fn _Qp_fle(a: *const f128, b: *const f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b))))) { - .Equal, .Less => true, - .Greater, .Unordered => false, - }; -} - -fn _Q_cmp(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, SparcFCMP, a, b)); -} - -fn _Q_feq(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Equal; -} - -fn _Q_fne(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) != .Equal; -} - -fn _Q_flt(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Less; -} - -fn _Q_fgt(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Greater; -} - -fn _Q_fge(a: f128, b: f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b))))) { - .Equal, .Greater => true, - .Less, .Unordered => false, - }; -} - -fn _Q_fle(a: f128, b: f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b))))) { - .Equal, .Less => true, - .Greater, .Unordered => false, - }; -} diff --git a/lib/compiler_rt/cmpxf2.zig b/lib/compiler_rt/cmpxf2.zig deleted file mode 100644 index 8146cd83c2f05bff98a3a122de2431820d897a08..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmpxf2.zig +++ /dev/null @@ -1,49 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__eqxf2, "__eqxf2"); - symbol(&__nexf2, "__nexf2"); - symbol(&__lexf2, "__lexf2"); - symbol(&__cmpxf2, "__cmpxf2"); - symbol(&__ltxf2, "__ltxf2"); -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lexf2`, `__eqxf2`, `__nexf2`, `__cmpxf2`, -/// and `__ltxf2`. -fn __cmpxf2(a: f80, b: f80) callconv(.c) i32 { - return @backingInt(comparef.cmp_f80(comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __lexf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined -/// to have the same return value. -fn __eqxf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined -/// to have the same return value. -fn __nexf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __ltxf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} diff --git a/lib/compiler_rt/comparedf2_test.zig b/lib/compiler_rt/comparedf2_test.zig index dbae6bbeeca09ef401a17334d57f3f3be824c781..cb8a7b727f993f5b57d46e55cfffdafa1343cc78 100644 --- a/lib/compiler_rt/comparedf2_test.zig +++ b/lib/compiler_rt/comparedf2_test.zig @@ -5,52 +5,12 @@ const std = @import("std"); const builtin = @import("builtin"); -const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; -const __ledf2 = @import("./cmpdf2.zig").__ledf2; -const __ltdf2 = @import("./cmpdf2.zig").__ltdf2; -const __nedf2 = @import("./cmpdf2.zig").__nedf2; +const compiler_rt = @import("../compiler_rt.zig"); -const __gedf2 = @import("./gedf2.zig").__gedf2; -const __gtdf2 = @import("./gedf2.zig").__gtdf2; - -const __unorddf2 = @import("./unorddf2.zig").__unorddf2; - -const TestVector = struct { - a: f64, - b: f64, - eqReference: c_int, - geReference: c_int, - gtReference: c_int, - leReference: c_int, - ltReference: c_int, - neReference: c_int, - unReference: c_int, -}; - -fn test__cmpdf2(vector: TestVector) bool { - if (__eqdf2(vector.a, vector.b) != vector.eqReference) { - return false; - } - if (__gedf2(vector.a, vector.b) != vector.geReference) { - return false; - } - if (__gtdf2(vector.a, vector.b) != vector.gtReference) { - return false; - } - if (__ledf2(vector.a, vector.b) != vector.leReference) { - return false; - } - if (__ltdf2(vector.a, vector.b) != vector.ltReference) { - return false; - } - if (__nedf2(vector.a, vector.b) != vector.neReference) { - return false; - } - if (__unorddf2(vector.a, vector.b) != vector.unReference) { - return false; - } - return true; -} +const impl = @import("comparef.zig"); +const Order = impl.Order; +const cmp_f64 = impl.cmp_f64; +const unord_f64 = impl.unord_f64; const arguments = [_]f64{ std.math.nan(f64), @@ -73,36 +33,20 @@ const arguments = [_]f64{ std.math.inf(f64), }; -fn generateVector(comptime a: f64, comptime b: f64) TestVector { - const leResult = if (a < b) -1 else if (a == b) 0 else 1; - const geResult = if (a > b) 1 else if (a == b) 0 else -1; - const unResult = if (a != a or b != b) 1 else 0; - return TestVector{ - .a = a, - .b = b, - .eqReference = leResult, - .geReference = geResult, - .gtReference = geResult, - .leReference = leResult, - .ltReference = leResult, - .neReference = leResult, - .unReference = unResult, - }; -} - -const test_vectors = init: { - @setEvalBranchQuota(10000); - var vectors: [arguments.len * arguments.len]TestVector = undefined; +test "compare f64" { for (arguments[0..], 0..) |arg_i, i| { for (arguments[0..], 0..) |arg_j, j| { - vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + const expected_unord = i == 0 or j == 0; + const expected_order: ?Order = if (expected_unord) null else switch (std.math.order( + if (i >= 9) i - 1 else i, + if (j >= 9) j - 1 else j, + )) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; + try std.testing.expect(expected_order == cmp_f64(arg_i, arg_j)); + try std.testing.expect(expected_unord == unord_f64(arg_i, arg_j)); } } - break :init vectors; -}; - -test "compare f64" { - for (test_vectors) |vector| { - try std.testing.expect(test__cmpdf2(vector)); - } } diff --git a/lib/compiler_rt/comparef.zig b/lib/compiler_rt/comparef.zig index a0f7551c74c9068909ef9e10c0ea71fa93140eef..d230e9a6b42f8ef88114e4d72b838f3f47c01cec 100644 --- a/lib/compiler_rt/comparef.zig +++ b/lib/compiler_rt/comparef.zig @@ -1,163 +1,309 @@ +const builtin = @import("builtin"); const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; +const Unordered = if (builtin.cpu.arch == .avr) + i8 +else if (builtin.cpu.arch.isAARCH64()) + i32 +else if (builtin.target.cTypeBitSize(.long).? >= builtin.target.ptrBitWidth()) + c_long +else + c_longlong; +pub const Order = enum(Unordered) { lt = -1, eq = 0, gt = 1 }; +const SparcOrder = enum(i32) { eq = 0, lt = 1, gt = 2, un = 3 }; + comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fcmpun, "__aeabi_fcmpun"); - } else { - symbol(&__unordsf2, "__unordsf2"); - } - - symbol(&__unordxf2, "__unordxf2"); - - symbol(&__eqhf2, "__eqhf2"); - symbol(&__nehf2, "__nehf2"); - symbol(&__lehf2, "__lehf2"); symbol(&__cmphf2, "__cmphf2"); - symbol(&__lthf2, "__lthf2"); + symbol(&__cmphf2, "__eqhf2"); + symbol(&__cmphf2, "__nehf2"); + symbol(&__cmphf2, "__lthf2"); + symbol(&__cmphf2, "__lehf2"); + symbol(&__gehf2, "__gthf2"); + symbol(&__gehf2, "__gehf2"); + symbol(&__unordhf2, "__unordhf2"); if (compiler_rt.want_aeabi) { symbol(&__aeabi_fcmpeq, "__aeabi_fcmpeq"); symbol(&__aeabi_fcmplt, "__aeabi_fcmplt"); symbol(&__aeabi_fcmple, "__aeabi_fcmple"); + symbol(&__aeabi_fcmpgt, "__aeabi_fcmpgt"); + symbol(&__aeabi_fcmpge, "__aeabi_fcmpge"); + symbol(&__aeabi_fcmpun, "__aeabi_fcmpun"); + + symbol(&__aeabi_dcmpeq, "__aeabi_dcmpeq"); + symbol(&__aeabi_dcmplt, "__aeabi_dcmplt"); + symbol(&__aeabi_dcmple, "__aeabi_dcmple"); + symbol(&__aeabi_dcmpgt, "__aeabi_dcmpgt"); + symbol(&__aeabi_dcmpge, "__aeabi_dcmpge"); + symbol(&__aeabi_dcmpun, "__aeabi_dcmpun"); } else { - symbol(&__eqsf2, "__eqsf2"); - symbol(&__nesf2, "__nesf2"); - symbol(&__lesf2, "__lesf2"); symbol(&__cmpsf2, "__cmpsf2"); - symbol(&__ltsf2, "__ltsf2"); + symbol(&__cmpsf2, "__eqsf2"); + symbol(&__cmpsf2, "__nesf2"); + symbol(&__cmpsf2, "__ltsf2"); + symbol(&__cmpsf2, "__lesf2"); + symbol(&__gesf2, "__gtsf2"); + symbol(&__gesf2, "__gesf2"); + symbol(&__unordsf2, "__unordsf2"); + + symbol(&__cmpdf2, "__cmpdf2"); + symbol(&__cmpdf2, "__eqdf2"); + symbol(&__cmpdf2, "__nedf2"); + symbol(&__cmpdf2, "__ltdf2"); + symbol(&__cmpdf2, "__ledf2"); + symbol(&__gedf2, "__gtdf2"); + symbol(&__gedf2, "__gedf2"); + symbol(&__unorddf2, "__unorddf2"); } + symbol(&__cmpxf2, "__cmpxf2"); + symbol(&__cmpxf2, "__eqxf2"); + symbol(&__cmpxf2, "__nexf2"); + symbol(&__cmpxf2, "__ltxf2"); + symbol(&__cmpxf2, "__lexf2"); + symbol(&__gexf2, "__gtxf2"); + symbol(&__gexf2, "__gexf2"); + symbol(&__unordxf2, "__unordxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__cmptf2, "__eqkf2"); + symbol(&__cmptf2, "__nekf2"); + symbol(&__cmptf2, "__ltkf2"); + symbol(&__cmptf2, "__lekf2"); + symbol(&__getf2, "__gtkf2"); + symbol(&__getf2, "__gekf2"); symbol(&__unordtf2, "__unordkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_cmp, "_Qp_cmp"); + symbol(&_Qp_feq, "_Qp_feq"); + symbol(&_Qp_fne, "_Qp_fne"); + symbol(&_Qp_flt, "_Qp_flt"); + symbol(&_Qp_fle, "_Qp_fle"); + symbol(&_Qp_fgt, "_Qp_fgt"); + symbol(&_Qp_fge, "_Qp_fge"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&_Q_cmp, "_Q_cmp"); + symbol(&_Q_feq, "_Q_feq"); + symbol(&_Q_fne, "_Q_fne"); + symbol(&_Q_flt, "_Q_flt"); + symbol(&_Q_fle, "_Q_fle"); + symbol(&_Q_fgt, "_Q_fgt"); + symbol(&_Q_fge, "_Q_fge"); + } else { + symbol(&__cmptf2, "__cmptf2"); + symbol(&__cmptf2, "__eqtf2"); + symbol(&__cmptf2, "__netf2"); + symbol(&__cmptf2, "__lttf2"); + symbol(&__cmptf2, "__letf2"); + symbol(&__getf2, "__gttf2"); + symbol(&__getf2, "__getf2"); + symbol(&__unordtf2, "__unordtf2"); } - symbol(&__unordtf2, "__unordtf2"); - symbol(&__unordhf2, "__unordhf2"); } -pub fn __unordhf2(a: f16, b: f16) callconv(.c) i32 { - return unordcmp(f16, a, b); +fn __cmphf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Order { + return cmp_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b)) orelse .gt; } - -pub fn __unordtf2(a: f128, b: f128) callconv(.c) i32 { - return unordcmp(f128, a, b); +fn __gehf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Order { + return cmp_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b)) orelse .lt; } - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lesf2`, `__eqsf2`, `__nesf2`, `__cmpsf2`, -/// and `__ltsf2`. -fn __cmpsf2(a: f32, b: f32) callconv(.c) i32 { - return @backingInt(cmpf2(f32, LE, a, b)); +fn __unordhf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); } - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -pub fn __lesf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +pub fn cmp_f16(a: f16, b: f16) ?Order { + return cmpf2(f16, a, b); } - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined -/// to have the same return value. -pub fn __eqsf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +pub fn unord_f16(a: f16, b: f16) bool { + return unord(f16, a, b); } -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined -/// to have the same return value. -pub fn __nesf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +fn __cmpsf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Order { + return cmp_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b)) orelse .gt; } - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -pub fn __ltsf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); -} - fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) == .Equal); + return @intFromBool(cmp_f32(a, b) == .eq); } - fn __aeabi_fcmplt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) == .Less); + return @intFromBool(cmp_f32(a, b) == .lt); } - fn __aeabi_fcmple(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) != .Greater); + return @intFromBool(cmp_f32(a, b) orelse .gt != .gt); } - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lehf2`, `__eqhf2`, `__nehf2`, `__cmphf2`, -/// and `__lthf2`. -fn __cmphf2(a: f16, b: f16) callconv(.c) i32 { - return @backingInt(cmpf2(f16, LE, a, b)); +fn __gesf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Order { + return cmp_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b)) orelse .lt; } - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __lehf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __aeabi_fcmpge(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f32(a, b) orelse .lt != .lt); } - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined -/// to have the same return value. -fn __eqhf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f32(a, b) == .gt); } - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined -/// to have the same return value. -fn __nehf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __unordsf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); } - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __lthf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); -} - -fn __unordxf2(a: f80, b: f80) callconv(.c) i32 { - return unordcmp(f80, a, b); -} - -pub fn __unordsf2(a: f32, b: f32) callconv(.c) i32 { - return unordcmp(f32, a, b); -} - fn __aeabi_fcmpun(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return unordcmp(f32, a, b); + return @intFromBool(unord_f32(a, b)); } +pub fn cmp_f32(a: f32, b: f32) ?Order { + return cmpf2(f32, a, b); +} +pub fn unord_f32(a: f32, b: f32) bool { + return unord(f32, a, b); +} + +fn __cmpdf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Order { + return cmp_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b)) orelse .gt; +} +fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .eq); +} +fn __aeabi_dcmplt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .lt); +} +fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) orelse .gt != .gt); +} +fn __gedf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Order { + return cmp_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b)) orelse .lt; +} +fn __aeabi_dcmpge(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) orelse .lt != .lt); +} +fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .gt); +} +fn __unorddf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dcmpun(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(unord_f64(a, b)); +} +pub fn cmp_f64(a: f64, b: f64) ?Order { + return cmpf2(f64, a, b); +} +pub fn unord_f64(a: f64, b: f64) bool { + return unord(f64, a, b); +} + +fn __cmpxf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Order { + return cmp_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b)) orelse .gt; +} +fn __gexf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Order { + return cmp_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b)) orelse .lt; +} +fn __unordxf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn cmp_f80(a: f80, b: f80) ?Order { + const a_rep = std.math.F80.fromFloat(a); + const b_rep = std.math.F80.fromFloat(b); + const sig_bits = std.math.floatMantissaBits(f80); + const int_bit = 0x8000000000000000; + const sign_bit = 0x8000; + const special_exp = 0x7FFF; -pub const LE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, + // If either a or b is NaN, they are unordered. + if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or + (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) + return null; - const Unordered: LE = .Greater; -}; + // If a and b are both zeros, they are equal. + if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) + return .eq; -pub const GE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, + if (@intFromBool(a_rep.exp == b_rep.exp) & @intFromBool(a_rep.fraction == b_rep.fraction) != 0) { + return .eq; + } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { + // signs are different + if (@as(i16, @bitCast(a_rep.exp)) < @as(i16, @bitCast(b_rep.exp))) { + return .lt; + } else { + return .gt; + } + } else { + const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); + const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); + if ((a_fraction < b_fraction) == (a_rep.exp & sign_bit == 0)) { + return .lt; + } else { + return .gt; + } + } +} +pub fn unord_f80(a: f80, b: f80) bool { + return unord(f80, a, b); +} - const Unordered: GE = .Less; -}; +fn __cmptf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Order { + return cmp_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b)) orelse .gt; +} +fn __getf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Order { + return cmp_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b)) orelse .lt; +} +fn __unordtf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_cmp(a: *const f128, b: *const f128) callconv(.c) SparcOrder { + return switch (cmp_f128(a.*, b.*) orelse return .un) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; +} +fn _Qp_feq(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .eq); +} +fn _Qp_fne(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) != .eq); +} +fn _Qp_flt(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .lt); +} +fn _Qp_fle(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a.*, b.*) orelse .gt) != .gt); +} +fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .gt); +} +fn _Qp_fge(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a.*, b.*) orelse .lt) != .lt); +} +fn _Q_cmp(a: f128, b: f128) callconv(.c) SparcOrder { + return switch (cmp_f128(a, b) orelse return .un) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; +} +fn _Q_feq(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .eq); +} +fn _Q_fne(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) != .eq); +} +fn _Q_flt(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .lt); +} +fn _Q_fle(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a, b) orelse .gt) != .gt); +} +fn _Q_fgt(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .gt); +} +fn _Q_fge(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a, b) orelse .lt) != .lt); +} +pub fn cmp_f128(a: f128, b: f128) ?Order { + return cmpf2(f128, a, b); +} +pub fn unord_f128(a: f128, b: f128) bool { + return unord(f128, a, b); +} -pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { +inline fn cmpf2(comptime T: type, a: T, b: T) ?Order { const bits = @typeInfo(T).float.bits; const srep_t = @Int(.signed, bits); const rep_t = @Int(.unsigned, bits); @@ -175,81 +321,42 @@ pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { const bAbs = @as(rep_t, @bitCast(bInt)) & absMask; // If either a or b is NaN, they are unordered. - if (aAbs > infRep or bAbs > infRep) return RT.Unordered; + if (aAbs > infRep or bAbs > infRep) return null; // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) return .Equal; + if ((aAbs | bAbs) == 0) return .eq; // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a floating-point compare. if ((aInt & bInt) >= 0) { if (aInt < bInt) { - return .Less; + return .lt; } else if (aInt == bInt) { - return .Equal; - } else return .Greater; + return .eq; + } else return .gt; } else { // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). if (aInt > bInt) { - return .Less; + return .lt; } else if (aInt == bInt) { - return .Equal; - } else return .Greater; + return .eq; + } else return .gt; } } -pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { - const a_rep = std.math.F80.fromFloat(a); - const b_rep = std.math.F80.fromFloat(b); - const sig_bits = std.math.floatMantissaBits(f80); - const int_bit = 0x8000000000000000; - const sign_bit = 0x8000; - const special_exp = 0x7FFF; - - // If either a or b is NaN, they are unordered. - if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or - (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) - return RT.Unordered; - - // If a and b are both zeros, they are equal. - if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) - return .Equal; - - if (@intFromBool(a_rep.exp == b_rep.exp) & @intFromBool(a_rep.fraction == b_rep.fraction) != 0) { - return .Equal; - } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { - // signs are different - if (@as(i16, @bitCast(a_rep.exp)) < @as(i16, @bitCast(b_rep.exp))) { - return .Less; - } else { - return .Greater; - } - } else { - const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); - const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); - if ((a_fraction < b_fraction) == (a_rep.exp & sign_bit == 0)) { - return .Less; - } else { - return .Greater; - } - } -} - -test "cmp_f80" { - inline for (.{ LE, GE }) |RT| { - try std.testing.expect(cmp_f80(RT, 1.0, 1.0) == RT.Equal); - try std.testing.expect(cmp_f80(RT, 0.0, -0.0) == RT.Equal); - try std.testing.expect(cmp_f80(RT, 2.0, 4.0) == RT.Less); - try std.testing.expect(cmp_f80(RT, 2.0, -4.0) == RT.Greater); - try std.testing.expect(cmp_f80(RT, -2.0, -4.0) == RT.Greater); - try std.testing.expect(cmp_f80(RT, -2.0, 4.0) == RT.Less); - } +test cmp_f80 { + try std.testing.expect(cmp_f80(1.0, 1.0) == .eq); + try std.testing.expect(cmp_f80(0.0, -0.0) == .eq); + try std.testing.expect(cmp_f80(2.0, 4.0) == .lt); + try std.testing.expect(cmp_f80(2.0, -4.0) == .gt); + try std.testing.expect(cmp_f80(-2.0, -4.0) == .gt); + try std.testing.expect(cmp_f80(-2.0, 4.0) == .lt); } -pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { +inline fn unord(comptime T: type, a: T, b: T) bool { const rep_t = @Int(.unsigned, @typeInfo(T).float.bits); const significandBits = std.math.floatMantissaBits(T); @@ -261,7 +368,7 @@ pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { const aAbs: rep_t = @as(rep_t, @bitCast(a)) & absMask; const bAbs: rep_t = @as(rep_t, @bitCast(b)) & absMask; - return @intFromBool(aAbs > infRep or bAbs > infRep); + return aAbs > infRep or bAbs > infRep; } test { diff --git a/lib/compiler_rt/comparesf2_test.zig b/lib/compiler_rt/comparesf2_test.zig index d42e1ca6db124de615f2eb3a74eadfeb119992eb..5e34b00604b8f7d608cb6d21e51d8118d26d013b 100644 --- a/lib/compiler_rt/comparesf2_test.zig +++ b/lib/compiler_rt/comparesf2_test.zig @@ -5,52 +5,12 @@ const std = @import("std"); const builtin = @import("builtin"); -const __eqsf2 = @import("./comparef.zig").__eqsf2; -const __lesf2 = @import("./comparef.zig").__lesf2; -const __ltsf2 = @import("./comparef.zig").__ltsf2; -const __nesf2 = @import("./comparef.zig").__nesf2; +const compiler_rt = @import("../compiler_rt.zig"); -const __gesf2 = @import("./gesf2.zig").__gesf2; -const __gtsf2 = @import("./gesf2.zig").__gtsf2; - -const __unordsf2 = @import("./comparef.zig").__unordsf2; - -const TestVector = struct { - a: f32, - b: f32, - eqReference: c_int, - geReference: c_int, - gtReference: c_int, - leReference: c_int, - ltReference: c_int, - neReference: c_int, - unReference: c_int, -}; - -fn test__cmpsf2(vector: TestVector) bool { - if (__eqsf2(vector.a, vector.b) != vector.eqReference) { - return false; - } - if (__gesf2(vector.a, vector.b) != vector.geReference) { - return false; - } - if (__gtsf2(vector.a, vector.b) != vector.gtReference) { - return false; - } - if (__lesf2(vector.a, vector.b) != vector.leReference) { - return false; - } - if (__ltsf2(vector.a, vector.b) != vector.ltReference) { - return false; - } - if (__nesf2(vector.a, vector.b) != vector.neReference) { - return false; - } - if (__unordsf2(vector.a, vector.b) != vector.unReference) { - return false; - } - return true; -} +const impl = @import("comparef.zig"); +const Order = impl.Order; +const cmp_f32 = impl.cmp_f32; +const unord_f32 = impl.unord_f32; const arguments = [_]f32{ std.math.nan(f32), @@ -73,36 +33,20 @@ const arguments = [_]f32{ std.math.inf(f32), }; -fn generateVector(comptime a: f32, comptime b: f32) TestVector { - const leResult = if (a < b) -1 else if (a == b) 0 else 1; - const geResult = if (a > b) 1 else if (a == b) 0 else -1; - const unResult = if (a != a or b != b) 1 else 0; - return TestVector{ - .a = a, - .b = b, - .eqReference = leResult, - .geReference = geResult, - .gtReference = geResult, - .leReference = leResult, - .ltReference = leResult, - .neReference = leResult, - .unReference = unResult, - }; -} - -const test_vectors = init: { - @setEvalBranchQuota(10000); - var vectors: [arguments.len * arguments.len]TestVector = undefined; +test "compare f32" { for (arguments[0..], 0..) |arg_i, i| { for (arguments[0..], 0..) |arg_j, j| { - vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + const expected_unord = i == 0 or j == 0; + const expected_order: ?Order = if (expected_unord) null else switch (std.math.order( + i - @intFromBool(i >= 9), + j - @intFromBool(j >= 9), + )) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; + try std.testing.expect(expected_order == cmp_f32(arg_i, arg_j)); + try std.testing.expect(expected_unord == unord_f32(arg_i, arg_j)); } } - break :init vectors; -}; - -test "compare f32" { - for (test_vectors) |vector| { - try std.testing.expect(test__cmpsf2(vector)); - } } diff --git a/lib/compiler_rt/cos.zig b/lib/compiler_rt/cos.zig index a207f0244f941c3e6730f9e6f5891201840120cc..72ea9026472a1f8e31bca5cddc9e106cfd66155b 100644 --- a/lib/compiler_rt/cos.zig +++ b/lib/compiler_rt/cos.zig @@ -13,31 +13,34 @@ const expect = std.testing.expect; const expectApproxEqAbs = std.testing.expectApproxEqAbs; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; comptime { - symbol(&cosh, "__cosh"); - symbol(&cosl, "__cosl"); + symbol(&__cosh, "__cosh"); symbol(&cosf, "cosf"); symbol(&cos, "cos"); - symbol(&cosx, "__cosx"); - if (compiler_rt.want_ppc_abi) { - symbol(&cosq, "cosf128"); - } - symbol(&cosq, "cosq"); + symbol(&__cosx, "__cosx"); + symbol(&cosq, "cosf128"); symbol(&cosl, "cosl"); + symbol(&cosl, "__cosl"); // required by musl } -pub fn cosh(a: f16) callconv(.c) f16 { +fn __cosh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(cos_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn cos_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(cosf(a)); + return @floatCast(cos_f32(x)); } -pub fn cosf(x: f32) callconv(.c) f32 { +fn cosf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(cos_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn cos_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -94,7 +97,10 @@ pub fn cosf(x: f32) callconv(.c) f32 { }; } -pub fn cos(x: f64) callconv(.c) f64 { +fn cos(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(cos_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn cos_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -123,7 +129,10 @@ pub fn cos(x: f64) callconv(.c) f64 { }; } -pub fn cosx(x: f80) callconv(.c) f80 { +fn __cosx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(cos_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn cos_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -147,7 +156,10 @@ pub fn cosx(x: f80) callconv(.c) f80 { }; } -pub fn cosq(x: f128) callconv(.c) f128 { +fn cosq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(cos_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn cos_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -173,20 +185,21 @@ pub fn cosq(x: f128) callconv(.c) f128 { pub fn cosl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return cos(x), - 80 => return cosx(x), - 128 => return cosq(x), - else => @compileError("unreachable"), + 64 => return cos_f64(x), + 80 => return cos_f80(x), + 128 => return cos_f128(x), + else => comptime unreachable, } } fn testCosSpecial(comptime T: type) !void { const f = switch (T) { - f32 => cosf, - f64 => cos, - f80 => cosx, - f128 => cosq, - else => @compileError("unimplemented"), + f16 => cos_f16, + f32 => cos_f32, + f64 => cos_f64, + f80 => cos_f80, + f128 => cos_f128, + else => comptime unreachable, }; try expect(f(0.0) == 1.0); @@ -198,13 +211,13 @@ fn testCosSpecial(comptime T: type) !void { test "cos32.normal" { const epsilon = math.floatEps(f32); - try expectApproxEqAbs(@as(f32, 1.0), cosf(0.0), epsilon); - try expectApproxEqAbs(@as(f32, 0.9800666), cosf(0.2), epsilon); - try expectApproxEqAbs(@as(f32, 0.6276231), cosf(0.8923), epsilon); - try expectApproxEqAbs(@as(f32, 0.0707372), cosf(1.5), epsilon); - try expectApproxEqAbs(@as(f32, 0.0707372), cosf(-1.5), epsilon); - try expectApproxEqAbs(@as(f32, 0.96913195), cosf(37.45), epsilon); - try expectApproxEqAbs(@as(f32, 0.40079966), cosf(89.123), epsilon); + try expectApproxEqAbs(@as(f32, 1.0), cos_f32(0.0), epsilon); + try expectApproxEqAbs(@as(f32, 0.9800666), cos_f32(0.2), epsilon); + try expectApproxEqAbs(@as(f32, 0.6276231), cos_f32(0.8923), epsilon); + try expectApproxEqAbs(@as(f32, 0.0707372), cos_f32(1.5), epsilon); + try expectApproxEqAbs(@as(f32, 0.0707372), cos_f32(-1.5), epsilon); + try expectApproxEqAbs(@as(f32, 0.96913195), cos_f32(37.45), epsilon); + try expectApproxEqAbs(@as(f32, 0.40079966), cos_f32(89.123), epsilon); } test "cos32.special" { @@ -213,13 +226,13 @@ test "cos32.special" { test "cos64.normal" { const epsilon = math.floatEps(f64); - try expectApproxEqAbs(@as(f64, 1.0), cos(0.0), epsilon); - try expectApproxEqAbs(@as(f64, 0.9800665778412416), cos(0.2), epsilon); - try expectApproxEqAbs(@as(f64, 0.6276230983360804), cos(0.8923), epsilon); - try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(1.5), epsilon); - try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(-1.5), epsilon); - try expectApproxEqAbs(@as(f64, 0.9691317730707778), cos(37.45), epsilon); - try expectApproxEqAbs(@as(f64, 0.4008006809354791), cos(89.123), epsilon); + try expectApproxEqAbs(@as(f64, 1.0), cos_f64(0.0), epsilon); + try expectApproxEqAbs(@as(f64, 0.9800665778412416), cos_f64(0.2), epsilon); + try expectApproxEqAbs(@as(f64, 0.6276230983360804), cos_f64(0.8923), epsilon); + try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos_f64(1.5), epsilon); + try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos_f64(-1.5), epsilon); + try expectApproxEqAbs(@as(f64, 0.9691317730707778), cos_f64(37.45), epsilon); + try expectApproxEqAbs(@as(f64, 0.4008006809354791), cos_f64(89.123), epsilon); } test "cos64.special" { @@ -228,13 +241,13 @@ test "cos64.special" { test "cos80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 1.0), cosx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), cosx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), cosx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(-1.5), epsilon); - try expectApproxEqAbs(@as(f80, 0.9691317730707771246), cosx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 0.4008006809354834001), cosx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 1.0), cos_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), cos_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), cos_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cos_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cos_f80(-1.5), epsilon); + try expectApproxEqAbs(@as(f80, 0.9691317730707771246), cos_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 0.4008006809354834001), cos_f80(89.123), epsilon); } test "cos80.special" { @@ -243,13 +256,13 @@ test "cos80.special" { test "cos128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 1.0), cosq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), cosq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), cosq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(-1.5), epsilon); - try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), cosq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), cosq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 1.0), cos_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), cos_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), cos_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cos_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cos_f128(-1.5), epsilon); + try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), cos_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), cos_f128(89.123), epsilon); } test "cos128.special" { diff --git a/lib/compiler_rt/count0bits.zig b/lib/compiler_rt/count0bits.zig index a8d0445dc69276e4639211818eb42707a8782c6c..fca372b33b98865ec041ee3ca764a5d8207ae330 100644 --- a/lib/compiler_rt/count0bits.zig +++ b/lib/compiler_rt/count0bits.zig @@ -1,6 +1,7 @@ const builtin = @import("builtin"); const std = @import("std"); -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__clzsi2, "__clzsi2"); diff --git a/lib/compiler_rt/divc3.zig b/lib/compiler_rt/divc3.zig index 92d2b39f663d272bdb83042f69abcd6a91c2ba09..a76a63c7e0f9059a112dc5c3b4406349766351f6 100644 --- a/lib/compiler_rt/divc3.zig +++ b/lib/compiler_rt/divc3.zig @@ -7,12 +7,81 @@ const maxInt = std.math.maxInt; const minInt = std.math.minInt; const isFinite = std.math.isFinite; const copysign = std.math.copysign; -const Complex = @import("mulc3.zig").Complex; + +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const Complex = compiler_rt.Complex; + +comptime { + if (@import("builtin").zig_backend != .stage2_c) { + symbol(&__divhc3, "__divhc3"); + symbol(&__divsc3, "__divsc3"); + symbol(&__divdc3, "__divdc3"); + symbol(&__divxc3, "__divxc3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__divtc3, "__divkc3"); + } else { + symbol(&__divtc3, "__divtc3"); + } + } +} + +fn __divhc3(lhs_real: compiler_rt.f16.Abi, lhs_imag: compiler_rt.f16.Abi, rhs_real: compiler_rt.f16.Abi, rhs_imag: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.complex.Abi { + return compiler_rt.f16.complex.toAbi(div_cf16( + compiler_rt.f16.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f16.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf16(a: Complex(f16), b: Complex(f16)) Complex(f16) { + return divc3(f16, a, b); +} + +fn __divsc3(lhs_real: compiler_rt.f32.Abi, lhs_imag: compiler_rt.f32.Abi, rhs_real: compiler_rt.f32.Abi, rhs_imag: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.complex.Abi { + return compiler_rt.f32.complex.toAbi(div_cf32( + compiler_rt.f32.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f32.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf32(a: Complex(f32), b: Complex(f32)) Complex(f32) { + return divc3(f32, a, b); +} + +fn __divdc3(lhs_real: compiler_rt.f64.Abi, lhs_imag: compiler_rt.f64.Abi, rhs_real: compiler_rt.f64.Abi, rhs_imag: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.complex.Abi { + return compiler_rt.f64.complex.toAbi(div_cf64( + compiler_rt.f64.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f64.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf64(a: Complex(f64), b: Complex(f64)) Complex(f64) { + return divc3(f64, a, b); +} + +fn __divxc3(lhs_real: compiler_rt.f80.Abi, lhs_imag: compiler_rt.f80.Abi, rhs_real: compiler_rt.f80.Abi, rhs_imag: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.complex.Abi { + return compiler_rt.f80.complex.toAbi(div_cf80( + compiler_rt.f80.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f80.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf80(a: Complex(f80), b: Complex(f80)) Complex(f80) { + return divc3(f80, a, b); +} + +fn __divtc3(lhs_real: compiler_rt.f128.Abi, lhs_imag: compiler_rt.f128.Abi, rhs_real: compiler_rt.f128.Abi, rhs_imag: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.complex.Abi { + return compiler_rt.f128.complex.toAbi(div_cf128( + compiler_rt.f128.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f128.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf128(a: Complex(f128), b: Complex(f128)) Complex(f128) { + return divc3(f128, a, b); +} /// Implementation based on Annex G of C17 Standard (N2176) -pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { - var c = c_in; - var d = d_in; +inline fn divc3(comptime T: type, lhs: Complex(T), rhs: Complex(T)) Complex(T) { + const a = lhs.real; + const b = lhs.imag; + var c = rhs.real; + var d = rhs.imag; // logbw used to prevent under/over-flow const logbw = ilogb(@max(@abs(c), @abs(d))); @@ -23,7 +92,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { break :b logbw; } else 0; const denom = c * c + d * d; - const result = Complex(T){ + const result: Complex(T) = .{ .real = scalbn((a * c + b * d) / denom, -ilogbw), .imag = scalbn((b * c - a * d) / denom, -ilogbw), }; @@ -58,3 +127,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { return result; } + +test { + _ = @import("divc3_test.zig"); +} diff --git a/lib/compiler_rt/divc3_test.zig b/lib/compiler_rt/divc3_test.zig index d3c400d46cacb1f12ec677d0f5dd0fb661bace4d..277a879253eed991a5e2cfa8453e8d28ab589f21 100644 --- a/lib/compiler_rt/divc3_test.zig +++ b/lib/compiler_rt/divc3_test.zig @@ -2,76 +2,53 @@ const std = @import("std"); const math = std.math; const expect = std.testing.expect; -const Complex = @import("./mulc3.zig").Complex; -const __divhc3 = @import("./divhc3.zig").__divhc3; -const __divsc3 = @import("./divsc3.zig").__divsc3; -const __divdc3 = @import("./divdc3.zig").__divdc3; -const __divxc3 = @import("./divxc3.zig").__divxc3; -const __divtc3 = @import("./divtc3.zig").__divtc3; +const Complex = @import("../compiler_rt.zig").Complex; + +const impl = @import("divc3.zig"); +const div_cf16 = impl.div_cf16; +const div_cf32 = impl.div_cf32; +const div_cf64 = impl.div_cf64; +const div_cf80 = impl.div_cf80; +const div_cf128 = impl.div_cf128; test "divc3" { - try testDiv(f16, __divhc3); - try testDiv(f32, __divsc3); - try testDiv(f64, __divdc3); - try testDiv(f80, __divxc3); - try testDiv(f128, __divtc3); + try testDiv(f16, div_cf16); + try testDiv(f32, div_cf32); + try testDiv(f64, div_cf64); + try testDiv(f80, div_cf80); + try testDiv(f128, div_cf128); } -fn testDiv(comptime T: type, comptime f: fn (T, T, T, T) callconv(.c) Complex(T)) !void { +fn testDiv(comptime T: type, comptime f: fn (Complex(T), Complex(T)) Complex(T)) !void { { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -1.0, .imag = 0.0 }); try expect(result.real == -1.0); - try expect(result.imag == 0.0); + try expect(math.isNegativeZero(result.imag)); } { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -4.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -4.0, .imag = 0.0 }); try expect(result.real == -0.25); - try expect(result.imag == 0.0); + try expect(math.isNegativeZero(result.imag)); } { // if the first operand is an infinity and the second operand is a finite number, then the - // result of the / operator is an infinity; - const a: T = -math.inf(T); - const b: T = 0.0; - const c: T = -4.0; - const d: T = 1.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + // resultult of the / operator is an infinity; + const result = f(.{ .real = -math.inf(T), .imag = 0.0 }, .{ .real = -4.0, .imag = 1.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } { // if the first operand is a finite number and the second operand is an infinity, then the // result of the / operator is a zero; - const a: T = 17.2; - const b: T = 0.0; - const c: T = -math.inf(T); - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == -0.0); - try expect(result.imag == 0.0); + const result = f(.{ .real = 17.2, .imag = 0.0 }, .{ .real = -math.inf(T), .imag = 0.0 }); + try expect(math.isNegativeZero(result.real)); + try expect(math.isNegativeZero(result.imag)); } { // if the first operand is a nonzero finite number or an infinity and the second operand is // a zero, then the result of the / operator is an infinity - const a: T = 1.1; - const b: T = 0.1; - const c: T = 0.0; - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + const result = f(.{ .real = 1.1, .imag = 0.1 }, .{ .real = 0.0, .imag = 0.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } } diff --git a/lib/compiler_rt/divdc3.zig b/lib/compiler_rt/divdc3.zig deleted file mode 100644 index e26dd26d61552832bcd1d19c022e8b0455551a40..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divdc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divdc3, "__divdc3"); - } -} - -pub fn __divdc3(a: f64, b: f64, c: f64, d: f64) callconv(.c) Complex(f64) { - return divc3.divc3(f64, a, b, c, d); -} diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig index 3ad767dbf2292d403aa0e2aafbdaf20f80ff9571..90953e0d0616d6a211872eef0b0c18ba1ff0cdb4 100644 --- a/lib/compiler_rt/divdf3.zig +++ b/lib/compiler_rt/divdf3.zig @@ -17,15 +17,15 @@ comptime { } } -pub fn __divdf3(a: f64, b: f64) callconv(.c) f64 { - return div(a, b); +fn __divdf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(div_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); } fn __aeabi_ddiv(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return div(a, b); + return div_f64(a, b); } -inline fn div(a: f64, b: f64) f64 { +pub fn div_f64(a: f64, b: f64) f64 { const Z = @Int(.unsigned, 64); const SignedZ = @Int(.signed, 64); diff --git a/lib/compiler_rt/divdf3_test.zig b/lib/compiler_rt/divdf3_test.zig index 45de9b27ef794706fc6e0e297f4289be3ae549fc..cd927bafc4d28921e9fb0bf191537b43cb953986 100644 --- a/lib/compiler_rt/divdf3_test.zig +++ b/lib/compiler_rt/divdf3_test.zig @@ -6,7 +6,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divdf3 = @import("divdf3.zig").__divdf3; +const div_f64 = @import("divdf3.zig").div_f64; const nanRep: u64 = @as(u64, @bitCast(math.nan(f64))); const infRep: u64 = @as(u64, @bitCast(math.inf(f64))); @@ -30,7 +30,7 @@ fn compareResultD(result: f64, expected: u64) bool { } fn test__divdf3(a: f64, b: f64, expected: u64) !void { - const x = __divdf3(a, b); + const x = div_f64(a, b); const ret = compareResultD(x, expected); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divhc3.zig b/lib/compiler_rt/divhc3.zig deleted file mode 100644 index c9668f4ca8ae84840ab3ee65446b682b6223832b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divhc3.zig +++ /dev/null @@ -1,14 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divhc3, "__divhc3"); - } -} - -pub fn __divhc3(a: f16, b: f16, c: f16, d: f16) callconv(.c) Complex(f16) { - return divc3.divc3(f16, a, b, c, d); -} diff --git a/lib/compiler_rt/divhf3.zig b/lib/compiler_rt/divhf3.zig deleted file mode 100644 index fc2710ff2761fce7e8822583b86aefc562f98486..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divsf3 = @import("./divsf3.zig"); - -comptime { - symbol(&__divhf3, "__divhf3"); -} - -pub fn __divhf3(a: f16, b: f16) callconv(.c) f16 { - // TODO: more efficient implementation - return @floatCast(divsf3.__divsf3(a, b)); -} diff --git a/lib/compiler_rt/divmodei4.zig b/lib/compiler_rt/divmodei4.zig index 55c7ec5792549933d22e8962f58b8cb6e23a5d54..9198951fe554a89cd2f65c69ce3fea087952db0a 100644 --- a/lib/compiler_rt/divmodei4.zig +++ b/lib/compiler_rt/divmodei4.zig @@ -5,7 +5,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); const udivmod = @import("udivmodei4.zig").divmod; -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__divei4, "__divei4"); diff --git a/lib/compiler_rt/divsc3.zig b/lib/compiler_rt/divsc3.zig deleted file mode 100644 index 9378bfab8ce80584b3b5b1b6d1fbd70200ef6648..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divsc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divsc3, "__divsc3"); - } -} - -pub fn __divsc3(a: f32, b: f32, c: f32, d: f32) callconv(.c) Complex(f32) { - return divc3.divc3(f32, a, b, c, d); -} diff --git a/lib/compiler_rt/divsf3.zig b/lib/compiler_rt/divsf3.zig index c0fbcb92b743fff4e12db533d7694210e7ebb0a2..c86c860948d315b260498c959e4678f5f64b9e94 100644 --- a/lib/compiler_rt/divsf3.zig +++ b/lib/compiler_rt/divsf3.zig @@ -9,6 +9,7 @@ const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; comptime { + symbol(&__divhf3, "__divhf3"); if (compiler_rt.want_aeabi) { symbol(&__aeabi_fdiv, "__aeabi_fdiv"); } else { @@ -16,15 +17,23 @@ comptime { } } -pub fn __divsf3(a: f32, b: f32) callconv(.c) f32 { - return div(a, b); +fn __divhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(div_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn div_f16(a: f16, b: f16) f16 { + // TODO: more efficient implementation + return @floatCast(div_f32(a, b)); +} + +fn __divsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(div_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); } fn __aeabi_fdiv(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return div(a, b); + return div_f32(a, b); } -inline fn div(a: f32, b: f32) f32 { +pub fn div_f32(a: f32, b: f32) f32 { const Z = @Int(.unsigned, 32); const significandBits = std.math.floatMantissaBits(f32); diff --git a/lib/compiler_rt/divsf3_test.zig b/lib/compiler_rt/divsf3_test.zig index c457915e49cd41986f1470b2f868398cfad855e9..f12e152b31b41b1fd85d1f1493838dd68a43f983 100644 --- a/lib/compiler_rt/divsf3_test.zig +++ b/lib/compiler_rt/divsf3_test.zig @@ -6,7 +6,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divsf3 = @import("divsf3.zig").__divsf3; +const div_f32 = @import("divsf3.zig").div_f32; const nanRep: u32 = @as(u32, @bitCast(math.nan(f32))); const infRep: u32 = @as(u32, @bitCast(math.inf(f32))); @@ -30,7 +30,7 @@ fn compareResultF(result: f32, expected: u32) bool { } fn test__divsf3(a: f32, b: f32, expected: u32) !void { - const x = __divsf3(a, b); + const x = div_f32(a, b); const ret = compareResultF(x, expected); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divtc3.zig b/lib/compiler_rt/divtc3.zig deleted file mode 100644 index b0e0f35f5447488f4d15ba76ede68bab2425f96b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divtc3.zig +++ /dev/null @@ -1,16 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - if (compiler_rt.want_ppc_abi) - symbol(&__divtc3, "__divkc3"); - symbol(&__divtc3, "__divtc3"); - } -} - -pub fn __divtc3(a: f128, b: f128, c: f128, d: f128) callconv(.c) Complex(f128) { - return divc3.divc3(f128, a, b, c, d); -} diff --git a/lib/compiler_rt/divtf3.zig b/lib/compiler_rt/divtf3.zig index 3b6f648e3ac33e2fb3183bdd7fcb892ea239500c..9995a9bfd796070d9573ac050bf233c9646a5d98 100644 --- a/lib/compiler_rt/divtf3.zig +++ b/lib/compiler_rt/divtf3.zig @@ -13,19 +13,20 @@ comptime { symbol(&_Qp_div, "_Qp_div"); } else if (compiler_rt.want_sparc32_abi) { symbol(&__divtf3, "_Q_div"); + } else { + symbol(&__divtf3, "__divtf3"); } - symbol(&__divtf3, "__divtf3"); } -pub fn __divtf3(a: f128, b: f128) callconv(.c) f128 { - return div(a, b); +fn __divtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(div_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); } fn _Qp_div(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = div(a.*, b.*); + c.* = div_f128(a.*, b.*); } -inline fn div(a: f128, b: f128) f128 { +pub fn div_f128(a: f128, b: f128) f128 { const Z = @Int(.unsigned, 128); const significandBits = std.math.floatMantissaBits(f128); diff --git a/lib/compiler_rt/divtf3_test.zig b/lib/compiler_rt/divtf3_test.zig index 4d10e5c39d7dc61b1c317364750757148635543d..dfc7e1e954ea96eb6927f4c56179efc15fe4a2ee 100644 --- a/lib/compiler_rt/divtf3_test.zig +++ b/lib/compiler_rt/divtf3_test.zig @@ -2,7 +2,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divtf3 = @import("divtf3.zig").__divtf3; +const div_f128 = @import("divtf3.zig").div_f128; fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { const rep: u128 = @bitCast(result); @@ -24,7 +24,7 @@ fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { } fn test__divtf3(a: f128, b: f128, expectedHi: u64, expectedLo: u64) !void { - const x = __divtf3(a, b); + const x = div_f128(a, b); const ret = compareResultLD(x, expectedHi, expectedLo); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divxc3.zig b/lib/compiler_rt/divxc3.zig deleted file mode 100644 index 86c737a83931c6c34f73303eeaba00536d8e1bd4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divxc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divxc3, "__divxc3"); - } -} - -pub fn __divxc3(a: f80, b: f80, c: f80, d: f80) callconv(.c) Complex(f80) { - return divc3.divc3(f80, a, b, c, d); -} diff --git a/lib/compiler_rt/divxf3.zig b/lib/compiler_rt/divxf3.zig index fdf43dc83bce6adbb53995826c516aecd7310fe2..eb3fde6862ab3937e8828d729287a35ea9d3ead9 100644 --- a/lib/compiler_rt/divxf3.zig +++ b/lib/compiler_rt/divxf3.zig @@ -11,7 +11,10 @@ comptime { symbol(&__divxf3, "__divxf3"); } -pub fn __divxf3(a: f80, b: f80) callconv(.c) f80 { +fn __divxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(div_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn div_f80(a: f80, b: f80) f80 { const T = f80; const Z = @Int(.unsigned, @bitSizeOf(T)); diff --git a/lib/compiler_rt/divxf3_test.zig b/lib/compiler_rt/divxf3_test.zig index cb897a1014022d50e8cb93043749b033b56af55d..88d7cada4606920997b5b0030134aaab476da576 100644 --- a/lib/compiler_rt/divxf3_test.zig +++ b/lib/compiler_rt/divxf3_test.zig @@ -2,7 +2,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divxf3 = @import("divxf3.zig").__divxf3; +const div_f80 = @import("divxf3.zig").div_f80; const nanRep: u80 = @as(u80, @bitCast(math.nan(f80))); const infRep: u80 = @as(u80, @bitCast(math.inf(f80))); @@ -19,14 +19,14 @@ fn compareResult(result: f80, expected: u80) bool { } fn expect__divxf3_result(a: f80, b: f80, expected: u80) !void { - const x = __divxf3(a, b); + const x = div_f80(a, b); const ret = compareResult(x, expected); try testing.expect(ret == true); } fn test__divxf3(a: f80, b: f80) !void { const integerBit = 1 << math.floatFractionalBits(f80); - const x = __divxf3(a, b); + const x = div_f80(a, b); // Next float (assuming normal, non-zero result) const x_plus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) + 1) | integerBit); diff --git a/lib/compiler_rt/exp.zig b/lib/compiler_rt/exp.zig index ce2eadb7f1edfe49ca51562a8b3ec4432f2017eb..6f9d19ddb3adbfe743fd278ce9e458ae45341502 100644 --- a/lib/compiler_rt/exp.zig +++ b/lib/compiler_rt/exp.zig @@ -14,26 +14,29 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__exph, "__exph"); symbol(&expf, "expf"); symbol(&exp, "exp"); symbol(&__expx, "__expx"); - if (compiler_rt.want_ppc_abi) { - symbol(&expq, "expf128"); - } - symbol(&expq, "expq"); + symbol(&expq, "expf128"); symbol(&expl, "expl"); } -pub fn __exph(a: f16) callconv(.c) f16 { +fn __exph(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(exp_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn exp_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(expf(a)); + return @floatCast(exp_f32(x)); } -pub fn expf(x_: f32) callconv(.c) f32 { +fn expf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(exp_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn exp_f32(x_: f32) f32 { const half = [_]f32{ 0.5, -0.5 }; const ln2hi = 6.9314575195e-1; const ln2lo = 1.4286067653e-6; @@ -108,7 +111,10 @@ pub fn expf(x_: f32) callconv(.c) f32 { } } -pub fn exp(x_: f64) callconv(.c) f64 { +fn exp(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(exp_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn exp_f64(x_: f64) f64 { const half = [_]f64{ 0.5, -0.5 }; const ln2hi: f64 = 6.93147180369123816490e-01; const ln2lo: f64 = 1.90821492927058770002e-10; @@ -189,116 +195,121 @@ pub fn exp(x_: f64) callconv(.c) f64 { } } -pub fn __expx(a: f80) callconv(.c) f80 { +fn __expx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(exp_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn exp_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(expq(a)); + return @floatCast(exp_f128(x)); } -const expq = @import("exp_f128.zig").exp; +fn expq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(exp_f128(compiler_rt.f128.fromAbi(x))); +} +pub const exp_f128 = @import("exp_f128.zig").exp; pub fn expl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return exp(x), - 80 => return __expx(x), - 128 => return expq(x), - else => @compileError("unreachable"), + 64 => return exp_f64(x), + 80 => return exp_f80(x), + 128 => return exp_f128(x), + else => comptime unreachable, } } test "expf() special" { - try expectEqual(expf(0.0), 1.0); - try expectEqual(expf(-0.0), 1.0); - try expectEqual(expf(1.0), math.e); - try expectEqual(expf(math.ln2), 2.0); - try expectEqual(expf(math.inf(f32)), math.inf(f32)); - try expect(math.isPositiveZero(expf(-math.inf(f32)))); - try expect(math.isNan(expf(math.nan(f32)))); - try expect(math.isNan(expf(math.snan(f32)))); + try expectEqual(exp_f32(0.0), 1.0); + try expectEqual(exp_f32(-0.0), 1.0); + try expectEqual(exp_f32(1.0), math.e); + try expectEqual(exp_f32(math.ln2), 2.0); + try expectEqual(exp_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isPositiveZero(exp_f32(-math.inf(f32)))); + try expect(math.isNan(exp_f32(math.nan(f32)))); + try expect(math.isNan(exp_f32(math.snan(f32)))); } test "expf() sanity" { - try expectEqual(expf(-0x1.0223a0p+3), 0x1.490320p-12); - try expectEqual(expf(0x1.161868p+2), 0x1.34712ap+6); - try expectEqual(expf(-0x1.0c34b4p+3), 0x1.e06b1ap-13); - try expectEqual(expf(-0x1.a206f0p+2), 0x1.7dd484p-10); - try expectEqual(expf(0x1.288bbcp+3), 0x1.4abc80p+13); - try expectEqual(expf(0x1.52efd0p-1), 0x1.f04a9cp+0); - try expectEqual(expf(-0x1.a05cc8p-2), 0x1.54f1e0p-1); - try expectEqual(expf(0x1.1f9efap-1), 0x1.c0f628p+0); - try expectEqual(expf(0x1.8c5db0p-1), 0x1.1599b2p+1); - try expectEqual(expf(-0x1.5b86eap-1), 0x1.03b572p-1); - try expectEqual(expf(-0x1.57f25cp+2), 0x1.2fbea2p-8); - try expectEqual(expf(0x1.c7d310p+3), 0x1.76eefp+20); - try expectEqual(expf(0x1.19be70p+4), 0x1.52d3dep+25); - try expectEqual(expf(-0x1.ab6d70p+3), 0x1.a88adep-20); - try expectEqual(expf(-0x1.5ac18ep+2), 0x1.22b328p-8); - try expectEqual(expf(-0x1.925982p-1), 0x1.d2acc0p-2); - try expectEqual(expf(0x1.7221cep+3), 0x1.9c2ceap+16); - try expectEqual(expf(0x1.11a0d4p+4), 0x1.980ee6p+24); - try expectEqual(expf(-0x1.ae41a2p+1), 0x1.1c28d0p-5); - try expectEqual(expf(-0x1.329154p+4), 0x1.47ef94p-28); + try expectEqual(exp_f32(-0x1.0223a0p+3), 0x1.490320p-12); + try expectEqual(exp_f32(0x1.161868p+2), 0x1.34712ap+6); + try expectEqual(exp_f32(-0x1.0c34b4p+3), 0x1.e06b1ap-13); + try expectEqual(exp_f32(-0x1.a206f0p+2), 0x1.7dd484p-10); + try expectEqual(exp_f32(0x1.288bbcp+3), 0x1.4abc80p+13); + try expectEqual(exp_f32(0x1.52efd0p-1), 0x1.f04a9cp+0); + try expectEqual(exp_f32(-0x1.a05cc8p-2), 0x1.54f1e0p-1); + try expectEqual(exp_f32(0x1.1f9efap-1), 0x1.c0f628p+0); + try expectEqual(exp_f32(0x1.8c5db0p-1), 0x1.1599b2p+1); + try expectEqual(exp_f32(-0x1.5b86eap-1), 0x1.03b572p-1); + try expectEqual(exp_f32(-0x1.57f25cp+2), 0x1.2fbea2p-8); + try expectEqual(exp_f32(0x1.c7d310p+3), 0x1.76eefp+20); + try expectEqual(exp_f32(0x1.19be70p+4), 0x1.52d3dep+25); + try expectEqual(exp_f32(-0x1.ab6d70p+3), 0x1.a88adep-20); + try expectEqual(exp_f32(-0x1.5ac18ep+2), 0x1.22b328p-8); + try expectEqual(exp_f32(-0x1.925982p-1), 0x1.d2acc0p-2); + try expectEqual(exp_f32(0x1.7221cep+3), 0x1.9c2ceap+16); + try expectEqual(exp_f32(0x1.11a0d4p+4), 0x1.980ee6p+24); + try expectEqual(exp_f32(-0x1.ae41a2p+1), 0x1.1c28d0p-5); + try expectEqual(exp_f32(-0x1.329154p+4), 0x1.47ef94p-28); } test "expf() boundary" { - try expectEqual(expf(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite - try expectEqual(expf(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf - try expectEqual(expf(0x1.fffffep+127), math.inf(f32)); // Max input value - try expectEqual(expf(0x1p-149), 1.0); // Min positive input value - try expectEqual(expf(-0x1p-149), 1.0); // Min negative input value - try expectEqual(expf(0x1p-126), 1.0); // First positive subnormal input - try expectEqual(expf(-0x1p-126), 1.0); // First negative subnormal input - try expectEqual(expf(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero - try expectEqual(expf(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero - try expectEqual(expf(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal - try expectEqual(expf(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal - + try expectEqual(exp_f32(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite + try expectEqual(exp_f32(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf + try expectEqual(exp_f32(0x1.fffffep+127), math.inf(f32)); // Max input value + try expectEqual(exp_f32(0x1p-149), 1.0); // Min positive input value + try expectEqual(exp_f32(-0x1p-149), 1.0); // Min negative input value + try expectEqual(exp_f32(0x1p-126), 1.0); // First positive subnormal input + try expectEqual(exp_f32(-0x1p-126), 1.0); // First negative subnormal input + try expectEqual(exp_f32(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero + try expectEqual(exp_f32(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero + try expectEqual(exp_f32(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal + try expectEqual(exp_f32(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal } test "exp() special" { - try expectEqual(exp(0.0), 1.0); - try expectEqual(exp(-0.0), 1.0); + try expectEqual(exp_f64(0.0), 1.0); + try expectEqual(exp_f64(-0.0), 1.0); // TODO: Accuracy error - off in the last bit in 64-bit, disagreeing with GCC // try expectEqual(exp(1.0), math.e); - try expectEqual(exp(math.ln2), 2.0); - try expectEqual(exp(math.inf(f64)), math.inf(f64)); - try expect(math.isPositiveZero(exp(-math.inf(f64)))); - try expect(math.isNan(exp(math.nan(f64)))); - try expect(math.isNan(exp(math.snan(f64)))); + try expectEqual(exp_f64(math.ln2), 2.0); + try expectEqual(exp_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isPositiveZero(exp_f64(-math.inf(f64)))); + try expect(math.isNan(exp_f64(math.nan(f64)))); + try expect(math.isNan(exp_f64(math.snan(f64)))); } test "exp() sanity" { - try expectEqual(exp(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12); - try expectEqual(exp(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6); - try expectEqual(exp(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13); - try expectEqual(exp(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10); - try expectEqual(exp(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13); - try expectEqual(exp(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0); - try expectEqual(exp(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1); - try expectEqual(exp(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0); - try expectEqual(exp(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1); - try expectEqual(exp(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1); - try expectEqual(exp(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8); - try expectEqual(exp(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20); - try expectEqual(exp(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25); - try expectEqual(exp(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20); - try expectEqual(exp(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8); - try expectEqual(exp(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2); - try expectEqual(exp(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16); - try expectEqual(exp(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24); - try expectEqual(exp(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5); - try expectEqual(exp(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28); + try expectEqual(exp_f64(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12); + try expectEqual(exp_f64(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6); + try expectEqual(exp_f64(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13); + try expectEqual(exp_f64(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10); + try expectEqual(exp_f64(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13); + try expectEqual(exp_f64(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0); + try expectEqual(exp_f64(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1); + try expectEqual(exp_f64(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0); + try expectEqual(exp_f64(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1); + try expectEqual(exp_f64(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1); + try expectEqual(exp_f64(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8); + try expectEqual(exp_f64(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20); + try expectEqual(exp_f64(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25); + try expectEqual(exp_f64(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20); + try expectEqual(exp_f64(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8); + try expectEqual(exp_f64(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2); + try expectEqual(exp_f64(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16); + try expectEqual(exp_f64(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24); + try expectEqual(exp_f64(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5); + try expectEqual(exp_f64(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28); } test "exp() boundary" { - try expectEqual(exp(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite - try expectEqual(exp(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf - try expectEqual(exp(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value - try expectEqual(exp(0x1p-1074), 1.0); // Min positive input value - try expectEqual(exp(-0x1p-1074), 1.0); // Min negative input value - try expectEqual(exp(0x1p-1022), 1.0); // First positive subnormal input - try expectEqual(exp(-0x1p-1022), 1.0); // First negative subnormal input - try expectEqual(exp(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero - try expectEqual(exp(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero - try expectEqual(exp(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal - try expectEqual(exp(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal + try expectEqual(exp_f64(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite + try expectEqual(exp_f64(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf + try expectEqual(exp_f64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value + try expectEqual(exp_f64(0x1p-1074), 1.0); // Min positive input value + try expectEqual(exp_f64(-0x1p-1074), 1.0); // Min negative input value + try expectEqual(exp_f64(0x1p-1022), 1.0); // First positive subnormal input + try expectEqual(exp_f64(-0x1p-1022), 1.0); // First negative subnormal input + try expectEqual(exp_f64(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero + try expectEqual(exp_f64(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero + try expectEqual(exp_f64(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal + try expectEqual(exp_f64(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal } diff --git a/lib/compiler_rt/exp2.zig b/lib/compiler_rt/exp2.zig index abcef881073619a860997766283c950cc702a3e6..4f25cdec63332788d1bdda417503901b02ce6154 100644 --- a/lib/compiler_rt/exp2.zig +++ b/lib/compiler_rt/exp2.zig @@ -19,19 +19,22 @@ comptime { symbol(&exp2f, "exp2f"); symbol(&exp2, "exp2"); symbol(&__exp2x, "__exp2x"); - if (compiler_rt.want_ppc_abi) { - symbol(&exp2q, "exp2f128"); - } - symbol(&exp2q, "exp2q"); + symbol(&exp2q, "exp2f128"); symbol(&exp2l, "exp2l"); } -pub fn __exp2h(x: f16) callconv(.c) f16 { +fn __exp2h(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(exp2_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn exp2_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(exp2f(x)); + return @floatCast(exp2_f32(x)); } -pub fn exp2f(x: f32) callconv(.c) f32 { +fn exp2f(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(exp2_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn exp2_f32(x: f32) f32 { const tblsiz: u32 = @intCast(exp2ft.len); const redux: f32 = 0x1.8p23 / @as(f32, @floatFromInt(tblsiz)); const P1: f32 = 0x1.62e430p-1; @@ -88,7 +91,10 @@ pub fn exp2f(x: f32) callconv(.c) f32 { return @floatCast(r * uk); } -pub fn exp2(x: f64) callconv(.c) f64 { +fn exp2(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(exp2_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn exp2_f64(x: f64) f64 { const tblsiz: u32 = @intCast(exp2dt.len / 2); const redux: f64 = 0x1.8p52 / @as(f64, @floatFromInt(tblsiz)); const P1: f64 = 0x1.62e42fefa39efp-1; @@ -156,19 +162,25 @@ pub fn exp2(x: f64) callconv(.c) f64 { return math.scalbn(r, ik); } -pub fn __exp2x(x: f80) callconv(.c) f80 { +fn __exp2x(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(exp2_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn exp2_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(exp2q(x)); + return @floatCast(exp2_f128(x)); } -pub const exp2q = @import("exp_f128.zig").exp2; +fn exp2q(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(exp2_f128(compiler_rt.f128.fromAbi(x))); +} +pub const exp2_f128 = @import("exp_f128.zig").exp2; pub fn exp2l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return exp2(x), - 80 => return __exp2x(x), - 128 => return exp2q(x), - else => @compileError("unreachable"), + 64 => return exp2_f64(x), + 80 => return exp2_f80(x), + 128 => return exp2_f128(x), + else => comptime unreachable, } } @@ -452,77 +464,77 @@ const exp2dt = [_]f64{ }; test "exp2f() special" { - try expectEqual(exp2f(0.0), 1.0); - try expectEqual(exp2f(-0.0), 1.0); - try expectEqual(exp2f(1.0), 2.0); - try expectEqual(exp2f(-1.0), 0.5); - try expectEqual(exp2f(math.inf(f32)), math.inf(f32)); - try expect(math.isPositiveZero(exp2f(-math.inf(f32)))); - try expect(math.isNan(exp2f(math.nan(f32)))); - try expect(math.isNan(exp2f(math.snan(f32)))); + try expectEqual(exp2_f32(0.0), 1.0); + try expectEqual(exp2_f32(-0.0), 1.0); + try expectEqual(exp2_f32(1.0), 2.0); + try expectEqual(exp2_f32(-1.0), 0.5); + try expectEqual(exp2_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isPositiveZero(exp2_f32(-math.inf(f32)))); + try expect(math.isNan(exp2_f32(math.nan(f32)))); + try expect(math.isNan(exp2_f32(math.snan(f32)))); } test "exp2f() sanity" { - try expectEqual(exp2f(-0x1.0223a0p+3), 0x1.e8d134p-9); - try expectEqual(exp2f(0x1.161868p+2), 0x1.453672p+4); - try expectEqual(exp2f(-0x1.0c34b4p+3), 0x1.890ca0p-9); - try expectEqual(exp2f(-0x1.a206f0p+2), 0x1.622d4ep-7); - try expectEqual(exp2f(0x1.288bbcp+3), 0x1.340ecep+9); - try expectEqual(exp2f(0x1.52efd0p-1), 0x1.950eeep+0); - try expectEqual(exp2f(-0x1.a05cc8p-2), 0x1.824056p-1); - try expectEqual(exp2f(0x1.1f9efap-1), 0x1.79dfa2p+0); - try expectEqual(exp2f(0x1.8c5db0p-1), 0x1.b5ceacp+0); - try expectEqual(exp2f(-0x1.5b86eap-1), 0x1.3fd8bap-1); + try expectEqual(exp2_f32(-0x1.0223a0p+3), 0x1.e8d134p-9); + try expectEqual(exp2_f32(0x1.161868p+2), 0x1.453672p+4); + try expectEqual(exp2_f32(-0x1.0c34b4p+3), 0x1.890ca0p-9); + try expectEqual(exp2_f32(-0x1.a206f0p+2), 0x1.622d4ep-7); + try expectEqual(exp2_f32(0x1.288bbcp+3), 0x1.340ecep+9); + try expectEqual(exp2_f32(0x1.52efd0p-1), 0x1.950eeep+0); + try expectEqual(exp2_f32(-0x1.a05cc8p-2), 0x1.824056p-1); + try expectEqual(exp2_f32(0x1.1f9efap-1), 0x1.79dfa2p+0); + try expectEqual(exp2_f32(0x1.8c5db0p-1), 0x1.b5ceacp+0); + try expectEqual(exp2_f32(-0x1.5b86eap-1), 0x1.3fd8bap-1); } test "exp2f() boundary" { - try expectEqual(exp2f(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite - try expectEqual(exp2f(0x1p+7), math.inf(f32)); // The first value that gives infinite result - try expectEqual(exp2f(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero - try expectEqual(exp2f(-0x1.2cp+7), 0); // The first value at which the result flushes to zero - try expectEqual(exp2f(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal - try expectEqual(exp2f(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal - try expectEqual(exp2f(0x1.fffffep+127), math.inf(f32)); // Max input value - try expectEqual(exp2f(0x1p-149), 1); // Min positive input value - try expectEqual(exp2f(-0x1p-149), 1); // Min negative input value - try expectEqual(exp2f(0x1p-126), 1); // First positive subnormal input - try expectEqual(exp2f(-0x1p-126), 1); // First negative subnormal input + try expectEqual(exp2_f32(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite + try expectEqual(exp2_f32(0x1p+7), math.inf(f32)); // The first value that gives infinite result + try expectEqual(exp2_f32(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero + try expectEqual(exp2_f32(-0x1.2cp+7), 0); // The first value at which the result flushes to zero + try expectEqual(exp2_f32(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal + try expectEqual(exp2_f32(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal + try expectEqual(exp2_f32(0x1.fffffep+127), math.inf(f32)); // Max input value + try expectEqual(exp2_f32(0x1p-149), 1); // Min positive input value + try expectEqual(exp2_f32(-0x1p-149), 1); // Min negative input value + try expectEqual(exp2_f32(0x1p-126), 1); // First positive subnormal input + try expectEqual(exp2_f32(-0x1p-126), 1); // First negative subnormal input } test "exp2() special" { - try expectEqual(exp2(0.0), 1.0); - try expectEqual(exp2(-0.0), 1.0); - try expectEqual(exp2(1.0), 2.0); - try expectEqual(exp2(-1.0), 0.5); - try expectEqual(exp2(math.inf(f64)), math.inf(f64)); - try expect(math.isPositiveZero(exp2(-math.inf(f64)))); - try expect(math.isNan(exp2(math.nan(f64)))); - try expect(math.isNan(exp2(math.snan(f64)))); + try expectEqual(exp2_f64(0.0), 1.0); + try expectEqual(exp2_f64(-0.0), 1.0); + try expectEqual(exp2_f64(1.0), 2.0); + try expectEqual(exp2_f64(-1.0), 0.5); + try expectEqual(exp2_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isPositiveZero(exp2_f64(-math.inf(f64)))); + try expect(math.isNan(exp2_f64(math.nan(f64)))); + try expect(math.isNan(exp2_f64(math.snan(f64)))); } test "exp2() sanity" { - try expectEqual(exp2(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9); - try expectEqual(exp2(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4); - try expectEqual(exp2(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9); - try expectEqual(exp2(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7); - try expectEqual(exp2(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9); - try expectEqual(exp2(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0); - try expectEqual(exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1); - try expectEqual(exp2(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0); - try expectEqual(exp2(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0); - try expectEqual(exp2(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1); + try expectEqual(exp2_f64(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9); + try expectEqual(exp2_f64(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4); + try expectEqual(exp2_f64(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9); + try expectEqual(exp2_f64(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7); + try expectEqual(exp2_f64(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9); + try expectEqual(exp2_f64(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0); + try expectEqual(exp2_f64(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1); + try expectEqual(exp2_f64(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0); + try expectEqual(exp2_f64(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0); + try expectEqual(exp2_f64(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1); } test "exp2() boundary" { - try expectEqual(exp2(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite - try expectEqual(exp2(0x1p+10), math.inf(f64)); // The first value that gives infinite result - try expectEqual(exp2(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero - try expectEqual(exp2(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero - try expectEqual(exp2(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal - try expectEqual(exp2(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal - try expectEqual(exp2(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value - try expectEqual(exp2(0x1p-1074), 1); // Min positive input value - try expectEqual(exp2(-0x1p-1074), 1); // Min negative input value - try expectEqual(exp2(0x1p-1022), 1); // First positive subnormal input - try expectEqual(exp2(-0x1p-1022), 1); // First negative subnormal input + try expectEqual(exp2_f64(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite + try expectEqual(exp2_f64(0x1p+10), math.inf(f64)); // The first value that gives infinite result + try expectEqual(exp2_f64(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero + try expectEqual(exp2_f64(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero + try expectEqual(exp2_f64(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal + try expectEqual(exp2_f64(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal + try expectEqual(exp2_f64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value + try expectEqual(exp2_f64(0x1p-1074), 1); // Min positive input value + try expectEqual(exp2_f64(-0x1p-1074), 1); // Min negative input value + try expectEqual(exp2_f64(0x1p-1022), 1); // First positive subnormal input + try expectEqual(exp2_f64(-0x1p-1022), 1); // First negative subnormal input } diff --git a/lib/compiler_rt/exp_f128.zig b/lib/compiler_rt/exp_f128.zig index ac09308ff30ee94c46403e4e7cd9f6afd0bea60c..c7a042c2b11edb228cd597eebdefcadbd3b689bd 100644 --- a/lib/compiler_rt/exp_f128.zig +++ b/lib/compiler_rt/exp_f128.zig @@ -26,7 +26,7 @@ const exp_f128 = @This(); const std = @import("std"); const math = std.math; -pub fn exp(x: f128) callconv(.c) f128 { +pub fn exp(x: f128) f128 { if (!math.isFinite(x)) { if (math.isNan(x)) { if (math.isSignalNan(x)) math.raiseInvalid(); @@ -91,7 +91,7 @@ fn expPoly(r_hi: f128, r_lo: f128) f128 { } /// Computes 2^x -pub fn exp2(x: f128) callconv(.c) f128 { +pub fn exp2(x: f128) f128 { if (!math.isFinite(x)) { if (math.isNan(x)) { if (math.isSignalNan(x)) math.raiseInvalid(); diff --git a/lib/compiler_rt/extenddftf2.zig b/lib/compiler_rt/extenddftf2.zig deleted file mode 100644 index d6267d7d8a93acd5a56d528d803f789a013dced5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extenddftf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const extendf = @import("./extendf.zig").extendf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__extenddftf2, "__extenddfkf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_dtoq, "_Qp_dtoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__extenddftf2, "_Q_dtoq"); - } - symbol(&__extenddftf2, "__extenddftf2"); -} - -pub fn __extenddftf2(a: f64) callconv(.c) f128 { - return extendf(f128, f64, @as(u64, @bitCast(a))); -} - -fn _Qp_dtoq(c: *f128, a: f64) callconv(.c) void { - c.* = extendf(f128, f64, @as(u64, @bitCast(a))); -} diff --git a/lib/compiler_rt/extenddfxf2.zig b/lib/compiler_rt/extenddfxf2.zig deleted file mode 100644 index d18195aea357d8fdd8fc26a0d34db798bc06f187..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extenddfxf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extenddfxf2, "__extenddfxf2"); -} - -pub fn __extenddfxf2(a: f64) callconv(.c) f80 { - return extend_f80(f64, @as(u64, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendf.zig b/lib/compiler_rt/extendf.zig index b923e9d25b7fe41a733b0aeb10db9d51b24176df..a0c637b352680a3b1bf1728c662bce3bdb6db91c 100644 --- a/lib/compiler_rt/extendf.zig +++ b/lib/compiler_rt/extendf.zig @@ -1,10 +1,175 @@ const std = @import("std"); -pub inline fn extendf( - comptime dst_t: type, - comptime src_t: type, - a: @Int(.unsigned, @typeInfo(src_t).float.bits), -) dst_t { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + if (compiler_rt.want_aeabi) { + if (compiler_rt.gnu_f16_abi) { + symbol(&__aeabi_h2f, "__gnu_h2f_ieee"); + } else { + symbol(&__aeabi_h2f, "__aeabi_h2f"); + } + } else if (compiler_rt.gnu_f16_abi) { + symbol(&__extendhfsf2, "__gnu_h2f_ieee"); + } + symbol(&__extendhfsf2, "__extendhfsf2"); + symbol(&__extendhfdf2, "__extendhfdf2"); + symbol(&__extendhfxf2, "__extendhfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extendhftf2, "__extendhfkf2"); + } else { + symbol(&__extendhftf2, "__extendhftf2"); + } + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2d, "__aeabi_f2d"); + } else { + symbol(&__extendsfdf2, "__extendsfdf2"); + } + symbol(&__extendsfxf2, "__extendsfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extendsftf2, "__extendsfkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_stoq, "_Qp_stoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__extendsftf2, "_Q_stoq"); + } else { + symbol(&__extendsftf2, "__extendsftf2"); + } + + symbol(&__extenddfxf2, "__extenddfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extenddftf2, "__extenddfkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_dtoq, "_Qp_dtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__extenddftf2, "_Q_dtoq"); + } else { + symbol(&__extenddftf2, "__extenddftf2"); + } + + if (compiler_rt.want_ppc_abi) { + symbol(&__extendxftf2, "__extendxfkf2"); + } else { + symbol(&__extendxftf2, "__extendxftf2"); + } +} + +fn __extendhfsf2(a: compiler_rt.f16Conv(f32).Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f16(compiler_rt.f16Conv(f32).fromAbi(a))); +} +fn __aeabi_h2f(a: u16) callconv(.{ .arm_aapcs = .{} }) u32 { + return @bitCast(f32_floatCast_f16(@bitCast(a))); +} +pub fn f32_floatCast_f16(a: f16) f32 { + return extendf(f32, f16, a); +} + +fn __extendhfdf2(a: compiler_rt.f16Conv(f64).Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f16(compiler_rt.f16Conv(f64).fromAbi(a))); +} +pub fn f64_floatCast_f16(a: f16) f64 { + return extendf(f64, f16, a); +} + +fn __extendhfxf2(a: compiler_rt.f16Conv(f80).Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f16(compiler_rt.f16Conv(f80).fromAbi(a))); +} +pub fn f80_floatCast_f16(a: f16) f80 { + return extend_f80(f16, a); +} + +fn __extendhftf2(a: compiler_rt.f16Conv(f128).Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f16(compiler_rt.f16Conv(f128).fromAbi(a))); +} +pub fn f128_floatCast_f16(a: f16) f128 { + return extendf(f128, f16, a); +} + +fn __extendsfdf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn __aeabi_f2d(a: f32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatCast_f32(a); +} +pub fn f64_floatCast_f32(a: f32) f64 { + return extendf(f64, f32, a); +} + +fn __extendsfxf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn f80_floatCast_f32(a: f32) f80 { + return extend_f80(f32, a); +} + +pub fn __extendsftf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn _Qp_stoq(c: *f128, a: f32) callconv(.c) void { + c.* = f128_floatCast_f32(a); +} +pub fn f128_floatCast_f32(a: f32) f128 { + return extendf(f128, f32, a); +} + +fn __extenddfxf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn f80_floatCast_f64(a: f64) f80 { + return extend_f80(f64, a); +} + +fn __extenddftf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn _Qp_dtoq(c: *f128, a: f64) callconv(.c) void { + c.* = f128_floatCast_f64(a); +} +pub fn f128_floatCast_f64(a: f64) f128 { + return extendf(f128, f64, a); +} + +fn __extendxftf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f128_floatCast_f80(a: f80) f128 { + const src_int_bit: u64 = 0x8000000000000000; + const src_sig_mask = ~src_int_bit; + const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + const dst_sig_bits = std.math.floatMantissaBits(f128); + + const dst_bits = @bitSizeOf(f128); + + // Break a into a sign and representation of the absolute value + var a_rep: std.math.F80 = .fromFloat(a); + const sign = a_rep.exp & 0x8000; + a_rep.exp &= 0x7FFF; + var abs_result: u128 = undefined; + + if (a_rep.exp == 0 and a_rep.fraction == 0) { + // zero + abs_result = 0; + } else if (a_rep.exp == 0x7FFF) { + // a is nan or infinite + abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else if (a_rep.fraction & src_int_bit != 0) { + // a is a normal value + abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else { + // a is denormal + abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); + } + + // Apply the signbit to (dst_t)abs(a). + const result: u128 = abs_result | @as(u128, sign) << (dst_bits - 16); + return @bitCast(result); +} + +inline fn extendf(comptime dst_t: type, comptime src_t: type, f: src_t) dst_t { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); @@ -31,6 +196,7 @@ pub inline fn extendf( const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; + const a: src_rep_t = @bitCast(f); // Break a into a sign and representation of the absolute value const aRep: src_rep_t = @bitCast(a); const aAbs: src_rep_t = aRep & srcAbsMask; @@ -66,11 +232,11 @@ pub inline fn extendf( } // Apply the signbit to (dst_t)abs(a). - const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); + const result: dst_rep_t = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); return @bitCast(result); } -pub inline fn extend_f80(comptime src_t: type, a: @Int(.unsigned, @typeInfo(src_t).float.bits)) f80 { +inline fn extend_f80(comptime src_t: type, f: src_t) f80 { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const src_sig_bits = std.math.floatMantissaBits(src_t); const dst_int_bit = 0x8000000000000000; @@ -92,6 +258,7 @@ pub inline fn extend_f80(comptime src_t: type, a: @Int(.unsigned, @typeInfo(src_ var dst: std.math.F80 = undefined; + const a: src_rep_t = @bitCast(f); // Break a into a sign and representation of the absolute value const a_abs = a & src_abs_mask; const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; diff --git a/lib/compiler_rt/extendf_test.zig b/lib/compiler_rt/extendf_test.zig index f572495b6634f8096fa5dd41dd9d2fd1b362a0a1..4cba105a6dc88b24230e9624d250b05da947edf2 100644 --- a/lib/compiler_rt/extendf_test.zig +++ b/lib/compiler_rt/extendf_test.zig @@ -1,31 +1,37 @@ const builtin = @import("builtin"); - const std = @import("std"); -const math = std.math; +const testing = std.testing; -const __extendhfsf2 = @import("extendhfsf2.zig").__extendhfsf2; -const __extendhftf2 = @import("extendhftf2.zig").__extendhftf2; -const __extendsftf2 = @import("extendsftf2.zig").__extendsftf2; -const __extenddftf2 = @import("extenddftf2.zig").__extenddftf2; -const __extenddfxf2 = @import("extenddfxf2.zig").__extenddfxf2; -const F16T = @import("../compiler_rt.zig").F16T; +const impl = @import("extendf.zig"); -fn test__extenddfxf2(a: f64, expected: u80) !void { - const x = __extenddfxf2(a); +const f32_floatCast_f16 = impl.f32_floatCast_f16; +const f64_floatCast_f16 = impl.f64_floatCast_f16; +const f80_floatCast_f16 = impl.f80_floatCast_f16; +const f128_floatCast_f16 = impl.f128_floatCast_f16; + +const f64_floatCast_f32 = impl.f64_floatCast_f32; +const f80_floatCast_f32 = impl.f80_floatCast_f32; +const f128_floatCast_f32 = impl.f128_floatCast_f32; + +const f80_floatCast_f64 = impl.f80_floatCast_f64; +const f128_floatCast_f64 = impl.f128_floatCast_f64; + +const f128_floatCast_f80 = impl.f128_floatCast_f80; + +fn test_f80_floatCast_f64(a: f64, expected: u80) !void { + const x = f80_floatCast_f64(a); const rep: u80 = @bitCast(x); if (rep == expected) return; - // test other possible NaN representation(signal NaN) - if (math.isNan(@as(f80, @bitCast(expected))) and math.isNan(x)) + if (std.math.isNan(@as(f80, @bitCast(expected))) and std.math.isNan(x)) return; - - @panic("__extenddfxf2 test failure"); + return error.TestFailure; } -fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { - const x = __extenddftf2(a); +fn test_f128_floatCast_f64(a: f64, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f64(a); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -33,7 +39,6 @@ fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { if (hi == expected_hi and lo == expected_lo) return; - // test other possible NaN representation(signal NaN) if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and @@ -42,12 +47,11 @@ fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { return; } } - - @panic("__extenddftf2 test failure"); + return error.TestFailure; } -fn test__extendhfsf2(a: u16, expected: u32) !void { - const x = __extendhfsf2(@as(F16T(f32), @bitCast(a))); +fn test_f32_floatCast_f16(a: u16, expected: u32) !void { + const x = f32_floatCast_f16(@bitCast(a)); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -58,12 +62,11 @@ fn test__extendhfsf2(a: u16, expected: u32) !void { return; } } - return error.TestFailure; } -fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { - const x = __extendsftf2(a); +fn test_f128_floatCast_f32(a: f32, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f32(a); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -71,7 +74,6 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { if (hi == expected_hi and lo == expected_lo) return; - // test other possible NaN representation(signal NaN) if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and @@ -80,111 +82,108 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { return; } } - return error.TestFailure; } -test "extenddfxf2" { +test f80_floatCast_f64 { // qNaN - try test__extenddfxf2(makeQNaN64(), 0x7fffc000000000000000); + try test_f80_floatCast_f64(makeQNaN64(), 0x7fffc000000000000000); // NaN - try test__extenddfxf2(makeNaN64(0x7100000000000), 0x7fffe080000000000000); + try test_f80_floatCast_f64(makeNaN64(0x7100000000000), 0x7fffe080000000000000); // This is bad? // inf - try test__extenddfxf2(makeInf64(), 0x7fff8000000000000000); + try test_f80_floatCast_f64(makeInf64(), 0x7fff8000000000000000); // zero - try test__extenddfxf2(0.0, 0x0); + try test_f80_floatCast_f64(0.0, 0x0); - try test__extenddfxf2(0x0.a3456789abcdefp+6, 0x4004a3456789abcdf000); + try test_f80_floatCast_f64(0x0.a3456789abcdefp+6, 0x4004a3456789abcdf000); - try test__extenddfxf2(0x0.edcba987654321fp-8, 0x3ff6edcba98765432000); + try test_f80_floatCast_f64(0x0.edcba987654321fp-8, 0x3ff6edcba98765432000); - try test__extenddfxf2(0x0.a3456789abcdefp+46, 0x402ca3456789abcdf000); + try test_f80_floatCast_f64(0x0.a3456789abcdefp+46, 0x402ca3456789abcdf000); - try test__extenddfxf2(0x0.edcba987654321fp-44, 0x3fd2edcba98765432000); + try test_f80_floatCast_f64(0x0.edcba987654321fp-44, 0x3fd2edcba98765432000); // subnormal - try test__extenddfxf2(0x1.8000000000001p-1022, 0x3c01c000000000000800); - try test__extenddfxf2(0x1.8000000000002p-1023, 0x3c00c000000000001000); + try test_f80_floatCast_f64(0x1.8000000000001p-1022, 0x3c01c000000000000800); + try test_f80_floatCast_f64(0x1.8000000000002p-1023, 0x3c00c000000000001000); } -test "extenddftf2" { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - +test f128_floatCast_f64 { // qNaN - try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0); + try test_f128_floatCast_f64(makeQNaN64(), 0x7fff800000000000, 0x0); // NaN - try test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); + try test_f128_floatCast_f64(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); // inf - try test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0); + try test_f128_floatCast_f64(makeInf64(), 0x7fff000000000000, 0x0); // zero - try test__extenddftf2(0.0, 0x0, 0x0); + try test_f128_floatCast_f64(0.0, 0x0, 0x0); - try test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); + try test_f128_floatCast_f64(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); - try test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); + try test_f128_floatCast_f64(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); - try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); + try test_f128_floatCast_f64(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); - try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); + try test_f128_floatCast_f64(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); // subnormal - try test__extenddftf2(0x1.8p-1022, 0x3c01800000000000, 0x0); - try test__extenddftf2(0x1.8p-1023, 0x3c00800000000000, 0x0); + try test_f128_floatCast_f64(0x1.8p-1022, 0x3c01800000000000, 0x0); + try test_f128_floatCast_f64(0x1.8p-1023, 0x3c00800000000000, 0x0); } -test "extendhfsf2" { - try test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN - try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN +test f32_floatCast_f16 { + try test_f32_floatCast_f16(0x7e00, 0x7fc00000); // qNaN + try test_f32_floatCast_f16(0x7f00, 0x7fe00000); // sNaN // On x86 the NaN becomes quiet because the return is pushed on the x87 // stack due to ABI requirements if (builtin.target.cpu.arch != .x86 and builtin.target.os.tag == .windows) - try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN + try test_f32_floatCast_f16(0x7c01, 0x7f802000); // sNaN - try test__extendhfsf2(0, 0); // 0 - try test__extendhfsf2(0x8000, 0x80000000); // -0 + try test_f32_floatCast_f16(0, 0); // 0 + try test_f32_floatCast_f16(0x8000, 0x80000000); // -0 - try test__extendhfsf2(0x7c00, 0x7f800000); // inf - try test__extendhfsf2(0xfc00, 0xff800000); // -inf + try test_f32_floatCast_f16(0x7c00, 0x7f800000); // inf + try test_f32_floatCast_f16(0xfc00, 0xff800000); // -inf - try test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24 - try test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24 + try test_f32_floatCast_f16(0x0001, 0x33800000); // denormal (min), 2**-24 + try test_f32_floatCast_f16(0x8001, 0xb3800000); // denormal (min), -2**-24 - try test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 - try test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 + try test_f32_floatCast_f16(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 + try test_f32_floatCast_f16(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 - try test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14 - try test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14 + try test_f32_floatCast_f16(0x0400, 0x38800000); // normal (min), 2**-14 + try test_f32_floatCast_f16(0x8400, 0xb8800000); // normal (min), -2**-14 - try test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504 - try test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504 + try test_f32_floatCast_f16(0x7bff, 0x477fe000); // normal (max), 65504 + try test_f32_floatCast_f16(0xfbff, 0xc77fe000); // normal (max), -65504 - try test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10 - try test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10 + try test_f32_floatCast_f16(0x3c01, 0x3f802000); // normal, 1 + 2**-10 + try test_f32_floatCast_f16(0xbc01, 0xbf802000); // normal, -1 - 2**-10 - try test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3 - try test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3 + try test_f32_floatCast_f16(0x3555, 0x3eaaa000); // normal, approx. 1/3 + try test_f32_floatCast_f16(0xb555, 0xbeaaa000); // normal, approx. -1/3 } -test "extendsftf2" { +test f128_floatCast_f32 { // qNaN - try test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0); + try test_f128_floatCast_f32(makeQNaN32(), 0x7fff800000000000, 0x0); // NaN - try test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0); + try test_f128_floatCast_f32(makeNaN32(0x410000), 0x7fff820000000000, 0x0); // inf - try test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0); + try test_f128_floatCast_f32(makeInf32(), 0x7fff000000000000, 0x0); // zero - try test__extendsftf2(0.0, 0x0, 0x0); - try test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); - try test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); + try test_f128_floatCast_f32(0.0, 0x0, 0x0); + try test_f128_floatCast_f32(0x1.23456p+5, 0x4004234560000000, 0x0); + try test_f128_floatCast_f32(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); + try test_f128_floatCast_f32(0x1.23456p+45, 0x402c234560000000, 0x0); + try test_f128_floatCast_f32(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); } fn makeQNaN64() f64 { @@ -211,8 +210,8 @@ fn makeInf32() f32 { return @bitCast(@as(u32, 0x7f800000)); } -fn test__extendhftf2(a: u16, expected_hi: u64, expected_lo: u64) !void { - const x = __extendhftf2(@as(F16T(f128), @bitCast(a))); +fn test_f128_floatCast_f16(a: u16, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f16(@bitCast(a)); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -233,26 +232,26 @@ fn test__extendhftf2(a: u16, expected_hi: u64, expected_lo: u64) !void { return error.TestFailure; } -test "extendhftf2" { +test f128_floatCast_f16 { // qNaN - try test__extendhftf2(0x7e00, 0x7fff800000000000, 0x0); + try test_f128_floatCast_f16(0x7e00, 0x7fff800000000000, 0x0); // NaN - try test__extendhftf2(0x7d00, 0x7fff400000000000, 0x0); + try test_f128_floatCast_f16(0x7d00, 0x7fff400000000000, 0x0); // inf - try test__extendhftf2(0x7c00, 0x7fff000000000000, 0x0); - try test__extendhftf2(0xfc00, 0xffff000000000000, 0x0); + try test_f128_floatCast_f16(0x7c00, 0x7fff000000000000, 0x0); + try test_f128_floatCast_f16(0xfc00, 0xffff000000000000, 0x0); // zero - try test__extendhftf2(0x0000, 0x0000000000000000, 0x0); - try test__extendhftf2(0x8000, 0x8000000000000000, 0x0); + try test_f128_floatCast_f16(0x0000, 0x0000000000000000, 0x0); + try test_f128_floatCast_f16(0x8000, 0x8000000000000000, 0x0); // denormal - try test__extendhftf2(0x0010, 0x3feb000000000000, 0x0); - try test__extendhftf2(0x0001, 0x3fe7000000000000, 0x0); - try test__extendhftf2(0x8001, 0xbfe7000000000000, 0x0); + try test_f128_floatCast_f16(0x0010, 0x3feb000000000000, 0x0); + try test_f128_floatCast_f16(0x0001, 0x3fe7000000000000, 0x0); + try test_f128_floatCast_f16(0x8001, 0xbfe7000000000000, 0x0); // pi - try test__extendhftf2(0x4248, 0x4000920000000000, 0x0); - try test__extendhftf2(0xc248, 0xc000920000000000, 0x0); + try test_f128_floatCast_f16(0x4248, 0x4000920000000000, 0x0); + try test_f128_floatCast_f16(0xc248, 0xc000920000000000, 0x0); - try test__extendhftf2(0x508c, 0x4004230000000000, 0x0); - try test__extendhftf2(0x1bb7, 0x3ff6edc000000000, 0x0); + try test_f128_floatCast_f16(0x508c, 0x4004230000000000, 0x0); + try test_f128_floatCast_f16(0x1bb7, 0x3ff6edc000000000, 0x0); } diff --git a/lib/compiler_rt/extendhfdf2.zig b/lib/compiler_rt/extendhfdf2.zig deleted file mode 100644 index 8cadc7139eebbad29f39b5245a14971c5c187a0d..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfdf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - symbol(&__extendhfdf2, "__extendhfdf2"); -} - -pub fn __extendhfdf2(a: compiler_rt.F16T(f64)) callconv(.c) f64 { - return extendf(f64, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhfsf2.zig b/lib/compiler_rt/extendhfsf2.zig deleted file mode 100644 index b638192c47502e6e698e86fcce8be3fbc0f7d2f9..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfsf2.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const extendf = @import("./extendf.zig").extendf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.gnu_f16_abi) { - symbol(&__gnu_h2f_ieee, "__gnu_h2f_ieee"); - } else if (compiler_rt.want_aeabi) { - symbol(&__aeabi_h2f, "__aeabi_h2f"); - } - symbol(&__extendhfsf2, "__extendhfsf2"); -} - -pub fn __extendhfsf2(a: compiler_rt.F16T(f32)) callconv(.c) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} - -fn __gnu_h2f_ieee(a: compiler_rt.F16T(f32)) callconv(.c) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} - -fn __aeabi_h2f(a: u16) callconv(.{ .arm_aapcs = .{} }) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhftf2.zig b/lib/compiler_rt/extendhftf2.zig deleted file mode 100644 index 29e7866b663389aae7048a474e585916fec7cac1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhftf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - symbol(&__extendhftf2, "__extendhftf2"); -} - -pub fn __extendhftf2(a: compiler_rt.F16T(f128)) callconv(.c) f128 { - return extendf(f128, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhfxf2.zig b/lib/compiler_rt/extendhfxf2.zig deleted file mode 100644 index e76daf4f55045262daa10cb4547688ed012a6bc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfxf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extendhfxf2, "__extendhfxf2"); -} - -fn __extendhfxf2(a: compiler_rt.F16T(f80)) callconv(.c) f80 { - return extend_f80(f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsfdf2.zig b/lib/compiler_rt/extendsfdf2.zig deleted file mode 100644 index 4f34b05242a5f57155c9bb83c3e978c6ec3ace42..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsfdf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2d, "__aeabi_f2d"); - } else { - symbol(&__extendsfdf2, "__extendsfdf2"); - } -} - -fn __extendsfdf2(a: f32) callconv(.c) f64 { - return extendf(f64, f32, @as(u32, @bitCast(a))); -} - -fn __aeabi_f2d(a: f32) callconv(.{ .arm_aapcs = .{} }) f64 { - return extendf(f64, f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsftf2.zig b/lib/compiler_rt/extendsftf2.zig deleted file mode 100644 index 6135065b14297e34c04e7cefec5b9387321089a7..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsftf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__extendsftf2, "__extendsfkf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_stoq, "_Qp_stoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__extendsftf2, "_Q_stoq"); - } - symbol(&__extendsftf2, "__extendsftf2"); -} - -pub fn __extendsftf2(a: f32) callconv(.c) f128 { - return extendf(f128, f32, @as(u32, @bitCast(a))); -} - -fn _Qp_stoq(c: *f128, a: f32) callconv(.c) void { - c.* = extendf(f128, f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsfxf2.zig b/lib/compiler_rt/extendsfxf2.zig deleted file mode 100644 index 9a6796bd668602b1d653a6581613fcb69edb7853..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsfxf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extendsfxf2, "__extendsfxf2"); -} - -fn __extendsfxf2(a: f32) callconv(.c) f80 { - return extend_f80(f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendxftf2.zig b/lib/compiler_rt/extendxftf2.zig deleted file mode 100644 index 1c39e1e84c7a3beb0a9470a123c05dea456eed77..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendxftf2.zig +++ /dev/null @@ -1,42 +0,0 @@ -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__extendxftf2, "__extendxftf2"); -} - -fn __extendxftf2(a: f80) callconv(.c) f128 { - const src_int_bit: u64 = 0x8000000000000000; - const src_sig_mask = ~src_int_bit; - const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - const dst_sig_bits = std.math.floatMantissaBits(f128); - - const dst_bits = @bitSizeOf(f128); - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.F80.fromFloat(a); - const sign = a_rep.exp & 0x8000; - a_rep.exp &= 0x7FFF; - var abs_result: u128 = undefined; - - if (a_rep.exp == 0 and a_rep.fraction == 0) { - // zero - abs_result = 0; - } else if (a_rep.exp == 0x7FFF) { - // a is nan or infinite - abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else if (a_rep.fraction & src_int_bit != 0) { - // a is a normal value - abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else { - // a is denormal - abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); - } - - // Apply the signbit to (dst_t)abs(a). - const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); - return @bitCast(result); -} diff --git a/lib/compiler_rt/fabs.zig b/lib/compiler_rt/fabs.zig index abdf21df8f33de1c080aba1452ae233287283540..2238e65e61292668cb2e7bc2e2be3f090470b2e9 100644 --- a/lib/compiler_rt/fabs.zig +++ b/lib/compiler_rt/fabs.zig @@ -9,39 +9,51 @@ comptime { symbol(&fabsf, "fabsf"); symbol(&fabs, "fabs"); symbol(&__fabsx, "__fabsx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fabsq, "fabsf128"); - } - symbol(&fabsq, "fabsq"); + symbol(&fabsq, "fabsf128"); symbol(&fabsl, "fabsl"); } -pub fn __fabsh(a: f16) callconv(.c) f16 { +fn __fabsh(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fabs_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn fabs_f16(a: f16) f16 { return generic_fabs(a); } -pub fn fabsf(a: f32) callconv(.c) f32 { +fn fabsf(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fabs_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn fabs_f32(a: f32) f32 { return generic_fabs(a); } -pub fn fabs(a: f64) callconv(.c) f64 { +fn fabs(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fabs_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn fabs_f64(a: f64) f64 { return generic_fabs(a); } -pub fn __fabsx(a: f80) callconv(.c) f80 { +fn __fabsx(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fabs_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn fabs_f80(a: f80) f80 { return generic_fabs(a); } -pub fn fabsq(a: f128) callconv(.c) f128 { +fn fabsq(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fabs_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn fabs_f128(a: f128) f128 { return generic_fabs(a); } pub fn fabsl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fabs(x), - 80 => return __fabsx(x), - 128 => return fabsq(x), - else => @compileError("unreachable"), + 64 => return fabs_f64(x), + 80 => return fabs_f80(x), + 128 => return fabs_f128(x), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fixdfdi.zig b/lib/compiler_rt/fixdfdi.zig deleted file mode 100644 index 5a66cc124f0f4ec092f1c49715ae6c547a396b66..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2lz, "__aeabi_d2lz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixdfdi, "__dtoi64"); - } - symbol(&__fixdfdi, "__fixdfdi"); - } -} - -pub fn __fixdfdi(a: f64) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn __aeabi_d2lz(a: f64) callconv(.{ .arm_aapcs = .{} }) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixdfei.zig b/lib/compiler_rt/fixdfei.zig deleted file mode 100644 index 170b4a160337fe5fc426fe2e715ab46426d76d7e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixdfei, "__fixdfei"); -} - -pub fn __fixdfei(r: [*]u8, bits: usize, a: f64) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixdfsi.zig b/lib/compiler_rt/fixdfsi.zig deleted file mode 100644 index 1d42337ea54573e4c7423147323046b029f9af52..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2iz, "__aeabi_d2iz"); - } else { - symbol(&__fixdfsi, "__fixdfsi"); - } -} - -pub fn __fixdfsi(a: f64) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn __aeabi_d2iz(a: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/fixdfti.zig b/lib/compiler_rt/fixdfti.zig deleted file mode 100644 index ff7434d63da148afc20b22bbfb54d6c1bdd17822..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixdfti, "__fixdfti"); -} - -pub fn __fixdfti(a: f64) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixhfei.zig b/lib/compiler_rt/fixhfei.zig deleted file mode 100644 index 5b759c3fc683d909ce7808242a59129c310bbb56..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixhfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixhfei, "__fixhfei"); -} - -pub fn __fixhfei(r: [*]u8, bits: usize, a: f16) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixint_test.zig b/lib/compiler_rt/fixint_test.zig deleted file mode 100644 index 198167ab867c22ed6160e83ed90920a6c5e97f28..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixint_test.zig +++ /dev/null @@ -1,149 +0,0 @@ -const std = @import("std"); -const math = std.math; -const testing = std.testing; - -const fixint = @import("fixint.zig").fixint; - -fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) !void { - const x = fixint(fp_t, fixint_t, a); - try testing.expect(x == expected); -} - -test "fixint.i1" { - try test__fixint(f32, i1, -math.inf(f32), -1); - try test__fixint(f32, i1, -math.floatMax(f32), -1); - try test__fixint(f32, i1, -2.0, -1); - try test__fixint(f32, i1, -1.1, -1); - try test__fixint(f32, i1, -1.0, -1); - try test__fixint(f32, i1, -0.9, 0); - try test__fixint(f32, i1, -0.1, 0); - try test__fixint(f32, i1, -math.floatMin(f32), 0); - try test__fixint(f32, i1, -0.0, 0); - try test__fixint(f32, i1, 0.0, 0); - try test__fixint(f32, i1, math.floatMin(f32), 0); - try test__fixint(f32, i1, 0.1, 0); - try test__fixint(f32, i1, 0.9, 0); - try test__fixint(f32, i1, 1.0, 0); - try test__fixint(f32, i1, 2.0, 0); - try test__fixint(f32, i1, math.floatMax(f32), 0); - try test__fixint(f32, i1, math.inf(f32), 0); -} - -test "fixint.i2" { - try test__fixint(f32, i2, -math.inf(f32), -2); - try test__fixint(f32, i2, -math.floatMax(f32), -2); - try test__fixint(f32, i2, -2.0, -2); - try test__fixint(f32, i2, -1.9, -1); - try test__fixint(f32, i2, -1.1, -1); - try test__fixint(f32, i2, -1.0, -1); - try test__fixint(f32, i2, -0.9, 0); - try test__fixint(f32, i2, -0.1, 0); - try test__fixint(f32, i2, -math.floatMin(f32), 0); - try test__fixint(f32, i2, -0.0, 0); - try test__fixint(f32, i2, 0.0, 0); - try test__fixint(f32, i2, math.floatMin(f32), 0); - try test__fixint(f32, i2, 0.1, 0); - try test__fixint(f32, i2, 0.9, 0); - try test__fixint(f32, i2, 1.0, 1); - try test__fixint(f32, i2, 2.0, 1); - try test__fixint(f32, i2, math.floatMax(f32), 1); - try test__fixint(f32, i2, math.inf(f32), 1); -} - -test "fixint.i3" { - try test__fixint(f32, i3, -math.inf(f32), -4); - try test__fixint(f32, i3, -math.floatMax(f32), -4); - try test__fixint(f32, i3, -4.0, -4); - try test__fixint(f32, i3, -3.0, -3); - try test__fixint(f32, i3, -2.0, -2); - try test__fixint(f32, i3, -1.9, -1); - try test__fixint(f32, i3, -1.1, -1); - try test__fixint(f32, i3, -1.0, -1); - try test__fixint(f32, i3, -0.9, 0); - try test__fixint(f32, i3, -0.1, 0); - try test__fixint(f32, i3, -math.floatMin(f32), 0); - try test__fixint(f32, i3, -0.0, 0); - try test__fixint(f32, i3, 0.0, 0); - try test__fixint(f32, i3, math.floatMin(f32), 0); - try test__fixint(f32, i3, 0.1, 0); - try test__fixint(f32, i3, 0.9, 0); - try test__fixint(f32, i3, 1.0, 1); - try test__fixint(f32, i3, 2.0, 2); - try test__fixint(f32, i3, 3.0, 3); - try test__fixint(f32, i3, 4.0, 3); - try test__fixint(f32, i3, math.floatMax(f32), 3); - try test__fixint(f32, i3, math.inf(f32), 3); -} - -test "fixint.i32" { - try test__fixint(f64, i32, -math.inf(f64), math.minInt(i32)); - try test__fixint(f64, i32, -math.floatMax(f64), math.minInt(i32)); - try test__fixint(f64, i32, @as(f64, math.minInt(i32)), math.minInt(i32)); - try test__fixint(f64, i32, @as(f64, math.minInt(i32)) + 1, math.minInt(i32) + 1); - try test__fixint(f64, i32, -2.0, -2); - try test__fixint(f64, i32, -1.9, -1); - try test__fixint(f64, i32, -1.1, -1); - try test__fixint(f64, i32, -1.0, -1); - try test__fixint(f64, i32, -0.9, 0); - try test__fixint(f64, i32, -0.1, 0); - try test__fixint(f64, i32, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i32, -0.0, 0); - try test__fixint(f64, i32, 0.0, 0); - try test__fixint(f64, i32, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i32, 0.1, 0); - try test__fixint(f64, i32, 0.9, 0); - try test__fixint(f64, i32, 1.0, 1); - try test__fixint(f64, i32, @as(f64, math.maxInt(i32)) - 1, math.maxInt(i32) - 1); - try test__fixint(f64, i32, @as(f64, math.maxInt(i32)), math.maxInt(i32)); - try test__fixint(f64, i32, math.floatMax(f64), math.maxInt(i32)); - try test__fixint(f64, i32, math.inf(f64), math.maxInt(i32)); -} - -test "fixint.i64" { - try test__fixint(f64, i64, -math.inf(f64), math.minInt(i64)); - try test__fixint(f64, i64, -math.floatMax(f64), math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64)), math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64)) + 1, math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64) / 2), math.minInt(i64) / 2); - try test__fixint(f64, i64, -2.0, -2); - try test__fixint(f64, i64, -1.9, -1); - try test__fixint(f64, i64, -1.1, -1); - try test__fixint(f64, i64, -1.0, -1); - try test__fixint(f64, i64, -0.9, 0); - try test__fixint(f64, i64, -0.1, 0); - try test__fixint(f64, i64, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i64, -0.0, 0); - try test__fixint(f64, i64, 0.0, 0); - try test__fixint(f64, i64, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i64, 0.1, 0); - try test__fixint(f64, i64, 0.9, 0); - try test__fixint(f64, i64, 1.0, 1); - try test__fixint(f64, i64, @as(f64, math.maxInt(i64)) - 1, math.maxInt(i64)); - try test__fixint(f64, i64, @as(f64, math.maxInt(i64)), math.maxInt(i64)); - try test__fixint(f64, i64, math.floatMax(f64), math.maxInt(i64)); - try test__fixint(f64, i64, math.inf(f64), math.maxInt(i64)); -} - -test "fixint.i128" { - try test__fixint(f64, i128, -math.inf(f64), math.minInt(i128)); - try test__fixint(f64, i128, -math.floatMax(f64), math.minInt(i128)); - try test__fixint(f64, i128, @as(f64, math.minInt(i128)), math.minInt(i128)); - try test__fixint(f64, i128, @as(f64, math.minInt(i128)) + 1, math.minInt(i128)); - try test__fixint(f64, i128, -2.0, -2); - try test__fixint(f64, i128, -1.9, -1); - try test__fixint(f64, i128, -1.1, -1); - try test__fixint(f64, i128, -1.0, -1); - try test__fixint(f64, i128, -0.9, 0); - try test__fixint(f64, i128, -0.1, 0); - try test__fixint(f64, i128, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i128, -0.0, 0); - try test__fixint(f64, i128, 0.0, 0); - try test__fixint(f64, i128, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i128, 0.1, 0); - try test__fixint(f64, i128, 0.9, 0); - try test__fixint(f64, i128, 1.0, 1); - try test__fixint(f64, i128, @as(f64, math.maxInt(i128)) - 1, math.maxInt(i128)); - try test__fixint(f64, i128, @as(f64, math.maxInt(i128)), math.maxInt(i128)); - try test__fixint(f64, i128, math.floatMax(f64), math.maxInt(i128)); - try test__fixint(f64, i128, math.inf(f64), math.maxInt(i128)); -} diff --git a/lib/compiler_rt/fixsfdi.zig b/lib/compiler_rt/fixsfdi.zig deleted file mode 100644 index 0a3731877e8bf7c7591391c8d76a6a5f953e74f1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2lz, "__aeabi_f2lz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixsfdi, "__stoi64"); - } - symbol(&__fixsfdi, "__fixsfdi"); - } -} - -pub fn __fixsfdi(a: f32) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn __aeabi_f2lz(a: f32) callconv(.{ .arm_aapcs = .{} }) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixsfei.zig b/lib/compiler_rt/fixsfei.zig deleted file mode 100644 index 43243254059d78d0ba678bcf1ae9ab37b50c3f47..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixsfei, "__fixsfei"); -} - -pub fn __fixsfei(r: [*]u8, bits: usize, a: f32) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixsfsi.zig b/lib/compiler_rt/fixsfsi.zig deleted file mode 100644 index 9c07c5824a25aac5f83ae2e2f58ce4df66f53b38..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2iz, "__aeabi_f2iz"); - } else { - symbol(&__fixsfsi, "__fixsfsi"); - } -} - -pub fn __fixsfsi(a: f32) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn __aeabi_f2iz(a: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/fixsfti.zig b/lib/compiler_rt/fixsfti.zig deleted file mode 100644 index 121eff084d58a00726ed140a0d4f4cacafdce87b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixsfti, "__fixsfti"); -} - -pub fn __fixsfti(a: f32) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixtfdi.zig b/lib/compiler_rt/fixtfdi.zig deleted file mode 100644 index d64682db1c1153d982acba2636b39f2b17e63753..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfdi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixtfdi, "__fixkfdi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtox, "_Qp_qtox"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixtfdi, "_Q_qtoll"); - } - symbol(&__fixtfdi, "__fixtfdi"); -} - -pub fn __fixtfdi(a: f128) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn _Qp_qtox(a: *const f128) callconv(.c) i64 { - return intFromFloat(i64, a.*); -} diff --git a/lib/compiler_rt/fixtfei.zig b/lib/compiler_rt/fixtfei.zig deleted file mode 100644 index 6443a0cb3be226c25affb17567fa8c860868aaa1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixtfei, "__fixtfei"); -} - -pub fn __fixtfei(r: [*]u8, bits: usize, a: f128) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixtfsi.zig b/lib/compiler_rt/fixtfsi.zig deleted file mode 100644 index 9acc5ec8eac8cb72a826c50d6d034e1ea48ef603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfsi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixtfsi, "__fixkfsi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoi, "_Qp_qtoi"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixtfsi, "_Q_qtoi"); - } - symbol(&__fixtfsi, "__fixtfsi"); -} - -pub fn __fixtfsi(a: f128) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn _Qp_qtoi(a: *const f128) callconv(.c) i32 { - return intFromFloat(i32, a.*); -} diff --git a/lib/compiler_rt/fixtfti.zig b/lib/compiler_rt/fixtfti.zig deleted file mode 100644 index 0aac298ca2c4d0fa3f8d7fd02cf1290f98929c2b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfti.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__fixtfti, "__fixkfti"); - symbol(&__fixtfti, "__fixtfti"); -} - -pub fn __fixtfti(a: f128) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixunsdfdi.zig b/lib/compiler_rt/fixunsdfdi.zig deleted file mode 100644 index 340bb8f6b11276fd9fff401b7f6a655e63d0a218..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2ulz, "__aeabi_d2ulz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixunsdfdi, "__dtou64"); - } - symbol(&__fixunsdfdi, "__fixunsdfdi"); - } -} - -pub fn __fixunsdfdi(a: f64) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn __aeabi_d2ulz(a: f64) callconv(.{ .arm_aapcs = .{} }) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunsdfei.zig b/lib/compiler_rt/fixunsdfei.zig deleted file mode 100644 index f564f7f7a32869e7cdad92a2f264941a3eab7511..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunsdfei, "__fixunsdfei"); -} - -pub fn __fixunsdfei(r: [*]u8, bits: usize, a: f64) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunsdfsi.zig b/lib/compiler_rt/fixunsdfsi.zig deleted file mode 100644 index e8b976d03d690d0de88d07e3fe4b97c0490e5901..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2uiz, "__aeabi_d2uiz"); - } else { - symbol(&__fixunsdfsi, "__fixunsdfsi"); - } -} - -pub fn __fixunsdfsi(a: f64) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn __aeabi_d2uiz(a: f64) callconv(.{ .arm_aapcs = .{} }) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunsdfti.zig b/lib/compiler_rt/fixunsdfti.zig deleted file mode 100644 index 1a634baaf5a6da399abaebb3e236ea5c02005ead..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsdfti, "__fixunsdfti"); -} - -pub fn __fixunsdfti(a: f64) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunshfdi.zig b/lib/compiler_rt/fixunshfdi.zig deleted file mode 100644 index 741e482506d2df3ffbb1388a9848f9317f6f1808..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunshfdi, "__fixunshfdi"); -} - -fn __fixunshfdi(a: f16) callconv(.c) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunshfei.zig b/lib/compiler_rt/fixunshfei.zig deleted file mode 100644 index a61d94f3958f4cc8f5f01f57f317e5a44f32fc20..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunshfei, "__fixunshfei"); -} - -pub fn __fixunshfei(r: [*]u8, bits: usize, a: f16) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunshfsi.zig b/lib/compiler_rt/fixunshfsi.zig deleted file mode 100644 index 438767c7a89a57c22385a1b666a6f59875d1f7ba..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunshfsi, "__fixunshfsi"); -} - -fn __fixunshfsi(a: f16) callconv(.c) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunshfti.zig b/lib/compiler_rt/fixunshfti.zig deleted file mode 100644 index 3dc7a5f99390d05606bb09298651e1d4482e3ab6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunshfti, "__fixunshfti"); -} - -pub fn __fixunshfti(a: f16) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunssfdi.zig b/lib/compiler_rt/fixunssfdi.zig deleted file mode 100644 index ffc238a53fb9f12a64446371a3d3191331d6994c..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2ulz, "__aeabi_f2ulz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixunssfdi, "__stou64"); - } - symbol(&__fixunssfdi, "__fixunssfdi"); - } -} - -pub fn __fixunssfdi(a: f32) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn __aeabi_f2ulz(a: f32) callconv(.{ .arm_aapcs = .{} }) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunssfei.zig b/lib/compiler_rt/fixunssfei.zig deleted file mode 100644 index 2fd123bd1b4693f96b51604a794dc2879660dc87..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunssfei, "__fixunssfei"); -} - -pub fn __fixunssfei(r: [*]u8, bits: usize, a: f32) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunssfsi.zig b/lib/compiler_rt/fixunssfsi.zig deleted file mode 100644 index f9c09b3f3d881774c21117e3c32b3a0b0b0a9f82..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2uiz, "__aeabi_f2uiz"); - } else { - symbol(&__fixunssfsi, "__fixunssfsi"); - } -} - -pub fn __fixunssfsi(a: f32) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn __aeabi_f2uiz(a: f32) callconv(.{ .arm_aapcs = .{} }) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunssfti.zig b/lib/compiler_rt/fixunssfti.zig deleted file mode 100644 index 6824afcde4b518642189696a47c0983047dd47c3..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunssfti, "__fixunssfti"); -} - -pub fn __fixunssfti(a: f32) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunstfdi.zig b/lib/compiler_rt/fixunstfdi.zig deleted file mode 100644 index c535bcc3583c93721f4fc07146f66edcc7611b01..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfdi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixunstfdi, "__fixunskfdi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoux, "_Qp_qtoux"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixunstfdi, "_Q_qtoull"); - } - symbol(&__fixunstfdi, "__fixunstfdi"); -} - -pub fn __fixunstfdi(a: f128) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn _Qp_qtoux(a: *const f128) callconv(.c) u64 { - return intFromFloat(u64, a.*); -} diff --git a/lib/compiler_rt/fixunstfei.zig b/lib/compiler_rt/fixunstfei.zig deleted file mode 100644 index 3d8986da90790a1a9cbf9a5fa2939e94c8009cc2..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunstfei, "__fixunstfei"); -} - -pub fn __fixunstfei(r: [*]u8, bits: usize, a: f128) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunstfsi.zig b/lib/compiler_rt/fixunstfsi.zig deleted file mode 100644 index d31cd759744d7616b30050335f70c50921a76ca9..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfsi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixunstfsi, "__fixunskfsi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoui, "_Qp_qtoui"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixunstfsi, "_Q_qtou"); - } - symbol(&__fixunstfsi, "__fixunstfsi"); -} - -pub fn __fixunstfsi(a: f128) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn _Qp_qtoui(a: *const f128) callconv(.c) u32 { - return intFromFloat(u32, a.*); -} diff --git a/lib/compiler_rt/fixunstfti.zig b/lib/compiler_rt/fixunstfti.zig deleted file mode 100644 index 78c6b1e8f7b90aa5d90a957920e949bb0aa2cbc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfti.zig +++ /dev/null @@ -1,14 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__fixunstfti, "__fixunskfti"); - symbol(&__fixunstfti, "__fixunstfti"); -} - -pub fn __fixunstfti(a: f128) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunsxfdi.zig b/lib/compiler_rt/fixunsxfdi.zig deleted file mode 100644 index 8385961b6b2ea2cd7632776ffa46d41e9e6f8bf3..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunsxfdi, "__fixunsxfdi"); -} - -fn __fixunsxfdi(a: f80) callconv(.c) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunsxfei.zig b/lib/compiler_rt/fixunsxfei.zig deleted file mode 100644 index d7902ddff54773d5240a57c8aaf6910ab6f9f02e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfei.zig +++ /dev/null @@ -1,13 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunsxfei, "__fixunsxfei"); -} - -pub fn __fixunsxfei(r: [*]u8, bits: usize, a: f80) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunsxfsi.zig b/lib/compiler_rt/fixunsxfsi.zig deleted file mode 100644 index 7309fbf5a6cf72a7eb862773fbb121437243c2ee..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsxfsi, "__fixunsxfsi"); -} - -fn __fixunsxfsi(a: f80) callconv(.c) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunsxfti.zig b/lib/compiler_rt/fixunsxfti.zig deleted file mode 100644 index 064c1352c9045870c1a984850f71c86fcf6e8e61..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsxfti, "__fixunsxfti"); -} - -pub fn __fixunsxfti(a: f80) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixxfdi.zig b/lib/compiler_rt/fixxfdi.zig deleted file mode 100644 index e9e4b7528b07168dafdf4791a6cc13d795d5b78a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixxfdi, "__fixxfdi"); -} - -fn __fixxfdi(a: f80) callconv(.c) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixxfei.zig b/lib/compiler_rt/fixxfei.zig deleted file mode 100644 index 82cd67648df13ac446de3a74ef796ba55ad45065..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixxfei, "__fixxfei"); -} - -pub fn __fixxfei(r: [*]u8, bits: usize, a: f80) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixxfsi.zig b/lib/compiler_rt/fixxfsi.zig deleted file mode 100644 index 363492168c760bcd12432e7c757ec4b8f60a2cc1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixxfsi, "__fixxfsi"); -} - -fn __fixxfsi(a: f80) callconv(.c) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/float_from_int.zig b/lib/compiler_rt/float_from_int.zig index 548d027accbb674e1ecbaeb77ef01a5491e256bc..898f246579c2902f5267d7e54c87422292931891 100644 --- a/lib/compiler_rt/float_from_int.zig +++ b/lib/compiler_rt/float_from_int.zig @@ -1,7 +1,475 @@ +const builtin = @import("builtin"); const std = @import("std"); const math = std.math; -pub fn floatFromInt(comptime T: type, x: anytype) T { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + symbol(&__floatsihf, "__floatsihf"); + symbol(&__floatdihf, "__floatdihf"); + symbol(&__floattihf, "__floattihf"); + symbol(&__floateihf, "__floateihf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_i2f, "__aeabi_i2f"); + symbol(&__aeabi_l2f, "__aeabi_l2f"); + } else { + symbol(&__floatsisf, "__floatsisf"); + symbol(&__floatdisf, "__floatdisf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatdisf, "__i64tos"); + } + symbol(&__floattisf, "__floattisf"); + symbol(&__floateisf, "__floateisf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_i2d, "__aeabi_i2d"); + symbol(&__aeabi_l2d, "__aeabi_l2d"); + } else { + symbol(&__floatsidf, "__floatsidf"); + symbol(&__floatdidf, "__floatdidf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatdidf, "__i64tod"); + } + symbol(&__floattidf, "__floattidf"); + symbol(&__floateidf, "__floateidf"); + + symbol(&__floatsixf, "__floatsixf"); + symbol(&__floatdixf, "__floatdixf"); + symbol(&__floattixf, "__floattixf"); + symbol(&__floateixf, "__floateixf"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__floatsitf, "__floatsikf"); + symbol(&__floatditf, "__floatdikf"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_itoq, "_Qp_itoq"); + symbol(&_Qp_xtoq, "_Qp_xtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__floatsitf, "_Q_itoq"); + symbol(&__floatditf, "_Q_lltoq"); + } else { + symbol(&__floatsitf, "__floatsitf"); + symbol(&__floatditf, "__floatditf"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__floattitf, "__floattikf"); + symbol(&__floateitf, "__floateikf"); + } else { + if (builtin.cpu.arch == .x86) { + symbol(&__floattitf_x86, "__floattitf"); + } else { + symbol(&__floattitf, "__floattitf"); + } + symbol(&__floateitf, "__floateitf"); + } +} + +fn __floatsihf(a: i32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i32(a)); +} +pub fn f16_floatFromInt_i32(a: i32) f16 { + return floatFromInt(f16, a); +} + +fn __floatdihf(a: i64) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i64(a)); +} +pub fn f16_floatFromInt_i64(a: i64) f16 { + return floatFromInt(f16, a); +} + +fn __floattihf(a: i128) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i128(a)); +} +pub fn f16_floatFromInt_i128(a: i128) f16 { + return floatFromInt(f16, a); +} + +fn __floateihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f16.toAbi(f16_floatFromInt_signed(a[0..byte_size])); +} +pub fn f16_floatFromInt_signed(a: []const u8) f16 { + return floatFromBigInt(f16, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsisf(a: i32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i32(a)); +} +fn __aeabi_i2f(a: i32) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_i32(a); +} +pub fn f32_floatFromInt_i32(a: i32) f32 { + return floatFromInt(f32, a); +} + +fn __floatdisf(a: i64) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i64(a)); +} +fn __aeabi_l2f(a: i64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_i64(a); +} +pub fn f32_floatFromInt_i64(a: i64) f32 { + return floatFromInt(f32, a); +} + +fn __floattisf(a: i128) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i128(a)); +} +pub fn f32_floatFromInt_i128(a: i128) f32 { + return floatFromInt(f32, a); +} + +fn __floateisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f32.toAbi(f32_floatFromInt_signed(a[0..byte_size])); +} +pub fn f32_floatFromInt_signed(a: []const u8) f32 { + return floatFromBigInt(f32, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsidf(a: i32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i32(a)); +} +fn __aeabi_i2d(a: i32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_i32(a); +} +pub fn f64_floatFromInt_i32(a: i32) f64 { + return floatFromInt(f64, a); +} + +fn __floatdidf(a: i64) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i64(a)); +} +fn __aeabi_l2d(a: i64) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_i64(a); +} +pub fn f64_floatFromInt_i64(a: i64) f64 { + return floatFromInt(f64, a); +} + +fn __floattidf(a: i128) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i128(a)); +} +pub fn f64_floatFromInt_i128(a: i128) f64 { + return floatFromInt(f64, a); +} + +fn __floateidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f64.toAbi(f64_floatFromInt_signed(a[0..byte_size])); +} +pub fn f64_floatFromInt_signed(a: []const u8) f64 { + return floatFromBigInt(f64, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsixf(a: i32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i32(a)); +} +pub fn f80_floatFromInt_i32(a: i32) f80 { + return floatFromInt(f80, a); +} + +fn __floatdixf(a: i64) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i64(a)); +} +pub fn f80_floatFromInt_i64(a: i64) f80 { + return floatFromInt(f80, a); +} + +fn __floattixf(a: i128) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i128(a)); +} +pub fn f80_floatFromInt_i128(a: i128) f80 { + return floatFromInt(f80, a); +} + +fn __floateixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f80.toAbi(f80_floatFromInt_signed(a[0..byte_size])); +} +pub fn f80_floatFromInt_signed(a: []const u8) f80 { + return floatFromBigInt(f80, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsitf(a: i32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i32(a)); +} +fn _Qp_itoq(c: *f128, a: i32) callconv(.c) void { + c.* = f128_floatFromInt_i32(a); +} +pub fn f128_floatFromInt_i32(a: i32) f128 { + return floatFromInt(f128, a); +} + +fn __floatditf(a: i64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i64(a)); +} +fn _Qp_xtoq(c: *f128, a: i64) callconv(.c) void { + c.* = f128_floatFromInt_i64(a); +} +pub fn f128_floatFromInt_i64(a: i64) f128 { + return floatFromInt(f128, a); +} + +fn __floattitf(a: i128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i128(a)); +} +fn __floattitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i128(@bitCast(a))); +} +pub fn f128_floatFromInt_i128(a: i128) f128 { + return floatFromInt(f128, a); +} + +fn __floateitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f128.toAbi(f128_floatFromInt_signed(a[0..byte_size])); +} +pub fn f128_floatFromInt_signed(a: []const u8) f128 { + return floatFromBigInt(f128, .signed, @ptrCast(@alignCast(a))); +} + +comptime { + symbol(&__floatunsihf, "__floatunsihf"); + symbol(&__floatundihf, "__floatundihf"); + symbol(&__floatuntihf, "__floatuntihf"); + symbol(&__floatuneihf, "__floatuneihf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ui2f, "__aeabi_ui2f"); + symbol(&__aeabi_ul2f, "__aeabi_ul2f"); + } else { + symbol(&__floatunsisf, "__floatunsisf"); + symbol(&__floatundisf, "__floatundisf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatundisf, "__u64tos"); + } + symbol(&__floatuntisf, "__floatuntisf"); + symbol(&__floatuneisf, "__floatuneisf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ui2d, "__aeabi_ui2d"); + } else { + symbol(&__floatunsidf, "__floatunsidf"); + } + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ul2d, "__aeabi_ul2d"); + } else { + if (compiler_rt.want_windows_arm_abi) { + symbol(&__floatundidf, "__u64tod"); + } + symbol(&__floatundidf, "__floatundidf"); + } + symbol(&__floatuntidf, "__floatuntidf"); + symbol(&__floatuneidf, "__floatuneidf"); + + symbol(&__floatunsixf, "__floatunsixf"); + symbol(&__floatundixf, "__floatundixf"); + symbol(&__floatuntixf, "__floatuntixf"); + symbol(&__floatuneixf, "__floatuneixf"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__floatunsitf, "__floatunsikf"); + symbol(&__floatunditf, "__floatundikf"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_uitoq, "_Qp_uitoq"); + symbol(&_Qp_uxtoq, "_Qp_uxtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__floatunsitf, "_Q_utoq"); + symbol(&__floatunditf, "_Q_ulltoq"); + } else { + symbol(&__floatunsitf, "__floatunsitf"); + symbol(&__floatunditf, "__floatunditf"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__floatuntitf, "__floatuntikf"); + symbol(&__floatuneitf, "__floatuneikf"); + } else { + if (builtin.cpu.arch == .x86) { + symbol(&__floatuntitf_x86, "__floatuntitf"); + } else if (builtin.cpu.arch == .x86_64 and + (builtin.os.tag == .windows or builtin.os.tag == .uefi)) + { + symbol(&__floatuntitf_x86_64_windows, "__floatuntitf"); + } else { + symbol(&__floatuntitf, "__floatuntitf"); + } + symbol(&__floatuneitf, "__floatuneitf"); + } +} + +fn __floatunsihf(a: u32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u32(a)); +} +pub fn f16_floatFromInt_u32(a: u32) f16 { + return floatFromInt(f16, a); +} + +fn __floatundihf(a: u64) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u64(a)); +} +pub fn f16_floatFromInt_u64(a: u64) f16 { + return floatFromInt(f16, a); +} + +fn __floatuntihf(a: u128) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u128(a)); +} +pub fn f16_floatFromInt_u128(a: u128) f16 { + return floatFromInt(f16, a); +} + +fn __floatuneihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f16.toAbi(f16_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f16_floatFromInt_unsigned(a: []const u8) f16 { + return floatFromBigInt(f16, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsisf(a: u32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u32(a)); +} +fn __aeabi_ui2f(a: u32) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_u32(a); +} +pub fn f32_floatFromInt_u32(a: u32) f32 { + return floatFromInt(f32, a); +} + +fn __floatundisf(a: u64) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u64(a)); +} +fn __aeabi_ul2f(a: u64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_u64(a); +} +pub fn f32_floatFromInt_u64(a: u64) f32 { + return floatFromInt(f32, a); +} + +fn __floatuntisf(a: u128) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u128(a)); +} +pub fn f32_floatFromInt_u128(a: u128) f32 { + return floatFromInt(f32, a); +} + +fn __floatuneisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f32.toAbi(f32_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f32_floatFromInt_unsigned(a: []const u8) f32 { + return floatFromBigInt(f32, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsidf(a: u32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u32(a)); +} +fn __aeabi_ui2d(a: u32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_u32(a); +} +pub fn f64_floatFromInt_u32(a: u32) f64 { + return floatFromInt(f64, a); +} + +fn __floatundidf(a: u64) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u64(a)); +} +fn __aeabi_ul2d(a: u64) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_u64(a); +} +pub fn f64_floatFromInt_u64(a: u64) f64 { + return floatFromInt(f64, a); +} + +fn __floatuntidf(a: u128) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u128(a)); +} +pub fn f64_floatFromInt_u128(a: u128) f64 { + return floatFromInt(f64, a); +} + +fn __floatuneidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f64.toAbi(f64_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f64_floatFromInt_unsigned(a: []const u8) f64 { + return floatFromBigInt(f64, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsixf(a: u32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u32(a)); +} +pub fn f80_floatFromInt_u32(a: u32) f80 { + return floatFromInt(f80, a); +} + +fn __floatundixf(a: u64) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u64(a)); +} +pub fn f80_floatFromInt_u64(a: u64) f80 { + return floatFromInt(f80, a); +} + +fn __floatuntixf(a: u128) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u128(a)); +} +pub fn f80_floatFromInt_u128(a: u128) f80 { + return floatFromInt(f80, a); +} + +fn __floatuneixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f80.toAbi(f80_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f80_floatFromInt_unsigned(a: []const u8) f80 { + return floatFromBigInt(f80, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsitf(a: u32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u32(a)); +} +fn _Qp_uitoq(c: *f128, a: u32) callconv(.c) void { + c.* = f128_floatFromInt_u32(a); +} +pub fn f128_floatFromInt_u32(a: u32) f128 { + return floatFromInt(f128, a); +} + +fn __floatunditf(a: u64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u64(a)); +} +fn _Qp_uxtoq(c: *f128, a: u64) callconv(.c) void { + c.* = f128_floatFromInt_u64(a); +} +pub fn f128_floatFromInt_u64(a: u64) f128 { + return floatFromInt(f128, a); +} + +fn __floatuntitf(a: u128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(a)); +} +fn __floatuntitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast(a))); +} +fn __floatuntitf_x86_64_windows(a_lo: u64, a_hi: u64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast( + packed struct { lo: u64, hi: u64 }{ .lo = a_lo, .hi = a_hi }, + ))); +} +pub fn f128_floatFromInt_u128(a: u128) f128 { + return floatFromInt(f128, a); +} + +fn __floatuneitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f128.toAbi(f128_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f128_floatFromInt_unsigned(a: []const u8) f128 { + return floatFromBigInt(f128, .unsigned, @ptrCast(@alignCast(a))); +} + +inline fn floatFromInt(comptime T: type, x: anytype) T { if (x == 0) return 0; // Various constants whose values follow from the type parameters. @@ -53,7 +521,7 @@ pub fn floatFromInt(comptime T: type, x: anytype) T { return @bitCast(sign_bit | result); } -const endian = @import("builtin").cpu.arch.endian(); +const endian = builtin.cpu.arch.endian(); inline fn limb(limbs: []const u32, index: usize) u32 { return switch (endian) { .little => limbs[index], @@ -61,11 +529,11 @@ inline fn limb(limbs: []const u32, index: usize) u32 { }; } -pub inline fn floatFromBigInt(comptime T: type, comptime signedness: std.builtin.Signedness, x: []const u32) T { +inline fn floatFromBigInt(comptime T: type, comptime signedness: std.lang.Signedness, x: []const u32) T { switch (x.len) { 0 => return 0, inline 1...4 => |limbs_len| { - const low_to_high: [limbs_len]u32 = switch (@import("builtin").cpu.arch.endian()) { + const low_to_high: [limbs_len]u32 = switch (endian) { .little => x[0..limbs_len].*, .big => switch (limbs_len) { 1 => .{x[0]}, diff --git a/lib/compiler_rt/float_from_int_test.zig b/lib/compiler_rt/float_from_int_test.zig index 8c908f420959b28fe107f290cb0bcb709c9ffd85..4ce3129f890f3f303d835733644afcf2fedbff4c 100644 --- a/lib/compiler_rt/float_from_int_test.zig +++ b/lib/compiler_rt/float_from_int_test.zig @@ -2,571 +2,593 @@ const std = @import("std"); const testing = std.testing; const math = std.math; -const __floatunsihf = @import("floatunsihf.zig").__floatunsihf; - -// Conversion to f32 -const __floatsisf = @import("floatsisf.zig").__floatsisf; -const __floatunsisf = @import("floatunsisf.zig").__floatunsisf; -const __floatdisf = @import("floatdisf.zig").__floatdisf; -const __floatundisf = @import("floatundisf.zig").__floatundisf; -const __floattisf = @import("floattisf.zig").__floattisf; -const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; -const __floateisf = @import("floateisf.zig").__floateisf; -const __floatuneisf = @import("floatuneisf.zig").__floatuneisf; - -// Conversion to f64 -const __floatsidf = @import("floatsidf.zig").__floatsidf; -const __floatunsidf = @import("floatunsidf.zig").__floatunsidf; -const __floatdidf = @import("floatdidf.zig").__floatdidf; -const __floatundidf = @import("floatundidf.zig").__floatundidf; -const __floattidf = @import("floattidf.zig").__floattidf; -const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; - -// Conversion to f128 -const __floatsitf = @import("floatsitf.zig").__floatsitf; -const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; -const __floatditf = @import("floatditf.zig").__floatditf; -const __floatunditf = @import("floatunditf.zig").__floatunditf; -const __floattitf = @import("floattitf.zig").__floattitf; -const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; - -fn test__floatsisf(a: i32, expected: u32) !void { - const r = __floatsisf(a); +const impl = @import("float_from_int.zig"); + +const f16_floatFromInt_i32 = impl.f16_floatFromInt_i32; +const f16_floatFromInt_u32 = impl.f16_floatFromInt_u32; +const f16_floatFromInt_i64 = impl.f16_floatFromInt_i64; +const f16_floatFromInt_u64 = impl.f16_floatFromInt_u64; +const f16_floatFromInt_i128 = impl.f16_floatFromInt_i128; +const f16_floatFromInt_u128 = impl.f16_floatFromInt_u128; +const f16_floatFromInt_signed = impl.f16_floatFromInt_signed; +const f16_floatFromInt_unsigned = impl.f16_floatFromInt_unsigned; + +const f32_floatFromInt_i32 = impl.f32_floatFromInt_i32; +const f32_floatFromInt_u32 = impl.f32_floatFromInt_u32; +const f32_floatFromInt_i64 = impl.f32_floatFromInt_i64; +const f32_floatFromInt_u64 = impl.f32_floatFromInt_u64; +const f32_floatFromInt_i128 = impl.f32_floatFromInt_i128; +const f32_floatFromInt_u128 = impl.f32_floatFromInt_u128; +const f32_floatFromInt_signed = impl.f32_floatFromInt_signed; +const f32_floatFromInt_unsigned = impl.f32_floatFromInt_unsigned; + +const f64_floatFromInt_i32 = impl.f64_floatFromInt_i32; +const f64_floatFromInt_u32 = impl.f64_floatFromInt_u32; +const f64_floatFromInt_i64 = impl.f64_floatFromInt_i64; +const f64_floatFromInt_u64 = impl.f64_floatFromInt_u64; +const f64_floatFromInt_i128 = impl.f64_floatFromInt_i128; +const f64_floatFromInt_u128 = impl.f64_floatFromInt_u128; +const f64_floatFromInt_signed = impl.f64_floatFromInt_signed; +const f64_floatFromInt_unsigned = impl.f64_floatFromInt_unsigned; + +const f80_floatFromInt_i32 = impl.f80_floatFromInt_i32; +const f80_floatFromInt_u32 = impl.f80_floatFromInt_u32; +const f80_floatFromInt_i64 = impl.f80_floatFromInt_i64; +const f80_floatFromInt_u64 = impl.f80_floatFromInt_u64; +const f80_floatFromInt_i128 = impl.f80_floatFromInt_i128; +const f80_floatFromInt_u128 = impl.f80_floatFromInt_u128; +const f80_floatFromInt_signed = impl.f80_floatFromInt_signed; +const f80_floatFromInt_unsigned = impl.f80_floatFromInt_unsigned; + +const f128_floatFromInt_i32 = impl.f128_floatFromInt_i32; +const f128_floatFromInt_u32 = impl.f128_floatFromInt_u32; +const f128_floatFromInt_i64 = impl.f128_floatFromInt_i64; +const f128_floatFromInt_u64 = impl.f128_floatFromInt_u64; +const f128_floatFromInt_i128 = impl.f128_floatFromInt_i128; +const f128_floatFromInt_u128 = impl.f128_floatFromInt_u128; +const f128_floatFromInt_signed = impl.f128_floatFromInt_signed; +const f128_floatFromInt_unsigned = impl.f128_floatFromInt_unsigned; + +fn test_f32_floatFromInt_i32(a: i32, expected: u32) !void { + const r = f32_floatFromInt_i32(a); try std.testing.expect(@as(u32, @bitCast(r)) == expected); } -fn test_one_floatunsisf(a: u32, expected: u32) !void { - const r = __floatunsisf(a); +fn test_f32_floatFromInt_u32(a: u32, expected: u32) !void { + const r = f32_floatFromInt_u32(a); try std.testing.expect(@as(u32, @bitCast(r)) == expected); } -test "floatsisf" { - try test__floatsisf(0, 0x00000000); - try test__floatsisf(1, 0x3f800000); - try test__floatsisf(-1, 0xbf800000); - try test__floatsisf(0x7FFFFFFF, 0x4f000000); - try test__floatsisf(@bitCast(@as(u32, @intCast(0x80000000))), 0xcf000000); +test f32_floatFromInt_i32 { + try test_f32_floatFromInt_i32(0, 0x00000000); + try test_f32_floatFromInt_i32(1, 0x3f800000); + try test_f32_floatFromInt_i32(-1, 0xbf800000); + try test_f32_floatFromInt_i32(0x7FFFFFFF, 0x4f000000); + try test_f32_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xcf000000); + + try testing.expect(f32_floatFromInt_i32(math.minInt(i32)) == math.minInt(i32)); } -test "floatunsisf" { +test f32_floatFromInt_u32 { // Test the produced bit pattern - try test_one_floatunsisf(0, 0); - try test_one_floatunsisf(1, 0x3f800000); - try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000); - try test_one_floatunsisf(0x80000000, 0x4f000000); - try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000); + try test_f32_floatFromInt_u32(0, 0); + try test_f32_floatFromInt_u32(1, 0x3f800000); + try test_f32_floatFromInt_u32(0x7FFFFFFF, 0x4f000000); + try test_f32_floatFromInt_u32(0x80000000, 0x4f000000); + try test_f32_floatFromInt_u32(0xFFFFFFFF, 0x4f800000); + + try testing.expect(f32_floatFromInt_u32(0) == 0.0); + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24)) == math.maxInt(u24)); + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u32)) == math.maxInt(u32) + 1); } -fn test__floatdisf(a: i64, expected: f32) !void { - const x = __floatdisf(a); +fn test_f32_floatFromInt_i64(a: i64, expected: f32) !void { + const x = f32_floatFromInt_i64(a); try testing.expect(x == expected); } -fn test__floatundisf(a: u64, expected: f32) !void { - try std.testing.expectEqual(expected, __floatundisf(a)); +fn test_f32_floatFromInt_u64(a: u64, expected: f32) !void { + const x = f32_floatFromInt_u64(a); + try testing.expect(x == expected); } -test "floatdisf" { - try test__floatdisf(0, 0.0); - try test__floatdisf(1, 1.0); - try test__floatdisf(2, 2.0); - try test__floatdisf(-1, -1.0); - try test__floatdisf(-2, -2.0); - try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000000000000000)), -0x1.000000p+63); - try test__floatdisf(@bitCast(@as(u64, 0x8000000000000001)), -0x1.000000p+63); - try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +test f32_floatFromInt_i64 { + try test_f32_floatFromInt_i64(0, 0.0); + try test_f32_floatFromInt_i64(1, 1.0); + try test_f32_floatFromInt_i64(2, 2.0); + try test_f32_floatFromInt_i64(-1, -1.0); + try test_f32_floatFromInt_i64(-2, -2.0); + try test_f32_floatFromInt_i64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_i64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000000)), -0x1.000000p+63); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000001)), -0x1.000000p+63); + try test_f32_floatFromInt_i64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_i64(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E4000000, 0x1.FEDCB8p+50); } -test "floatundisf" { - try test__floatundisf(0, 0.0); - try test__floatundisf(1, 1.0); - try test__floatundisf(2, 2.0); - try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundisf(0x8000008000000000, 0x1p+63); - try test__floatundisf(0x8000010000000000, 0x1.000002p+63); - try test__floatundisf(0x8000000000000000, 0x1p+63); - try test__floatundisf(0x8000000000000001, 0x1p+63); - try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); - try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +test f32_floatFromInt_u64 { + try test_f32_floatFromInt_u64(0, 0.0); + try test_f32_floatFromInt_u64(1, 1.0); + try test_f32_floatFromInt_u64(2, 2.0); + try test_f32_floatFromInt_u64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_u64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_u64(0x8000008000000000, 0x1p+63); + try test_f32_floatFromInt_u64(0x8000010000000000, 0x1.000002p+63); + try test_f32_floatFromInt_u64(0x8000000000000000, 0x1p+63); + try test_f32_floatFromInt_u64(0x8000000000000001, 0x1p+63); + try test_f32_floatFromInt_u64(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test_f32_floatFromInt_u64(0xFFFFFFFFFFFFFFFF, 0x1p+64); + try test_f32_floatFromInt_u64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_u64(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E4000000, 0x1.FEDCB8p+50); } -fn test__floattisf(a: i128, expected: f32) !void { - const x = __floattisf(a); +fn test_f32_floatFromInt_i128(a: i128, expected: f32) !void { + const x = f32_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntisf(a: u128, expected: f32) !void { - const x = __floatuntisf(a); +fn test_f32_floatFromInt_u128(a: u128, expected: f32) !void { + const x = f32_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattisf" { - try test__floattisf(0, 0.0); +test f32_floatFromInt_i128 { + try test_f32_floatFromInt_i128(0, 0.0); - try test__floattisf(1, 1.0); - try test__floattisf(2, 2.0); - try test__floattisf(-1, -1.0); - try test__floattisf(-2, -2.0); + try test_f32_floatFromInt_i128(1, 1.0); + try test_f32_floatFromInt_i128(2, 2.0); + try test_f32_floatFromInt_i128(-1, -1.0); + try test_f32_floatFromInt_i128(-2, -2.0); - try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); - try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + try test_f32_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB8p+50); - try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); - try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); } -test "floatuntisf" { - try test__floatuntisf(0, 0.0); +test f32_floatFromInt_u128 { + try test_f32_floatFromInt_u128(0, 0.0); - try test__floatuntisf(1, 1.0); - try test__floatuntisf(2, 2.0); - try test__floatuntisf(20, 20.0); + try test_f32_floatFromInt_u128(1, 1.0); + try test_f32_floatFromInt_u128(2, 2.0); + try test_f32_floatFromInt_u128(20, 20.0); - try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntisf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntisf(make_uti(0x8000000000000800, 0), 0x1.0p+127); - try test__floatuntisf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000000000000800, 0), 0x1.0p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - try test__floatuntisf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f32_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f32_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f32_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f32_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f32_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + try test_f32_floatFromInt_u128(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test_f32_floatFromInt_u128(0xFFFFFFFFFFFFFFFF, 0x1p+64); - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + try test_f32_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB8p+50); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); // Test overflow to infinity - try test__floatuntisf(math.maxInt(u128), @bitCast(math.inf(f32))); + try test_f32_floatFromInt_u128(math.maxInt(u128), @bitCast(math.inf(f32))); } -fn test_floateisf(expected: u32, comptime T: type, a: T) !void { +fn test_f32_floatFromInt(expected: u32, comptime T: type, a: T) !void { const int = @typeInfo(T).int; const r = switch (int.signedness) { - .signed => __floateisf, - .unsigned => __floatuneisf, - }(@ptrCast(&a), int.bits); + .signed => f32_floatFromInt_signed, + .unsigned => f32_floatFromInt_unsigned, + }(@ptrCast(&a)); try testing.expect(expected == @as(u32, @bitCast(r))); } -test "floateisf" { - try test_floateisf(0xFF000000, i256, -1 << 127); - try test_floateisf(0xFF000000, i256, -math.maxInt(u127)); - try test_floateisf(0xDF012347, i256, -0x8123468100000000); - try test_floateisf(0xDF012347, i256, -0x8123468000000001); - try test_floateisf(0xDF012346, i256, -0x8123468000000000); - try test_floateisf(0xDF012346, i256, -0x8123458100000000); - try test_floateisf(0xDF012346, i256, -0x8123458000000001); - try test_floateisf(0xDF012346, i256, -0x8123458000000000); - try test_floateisf(0xDF012345, i256, -0x8123456789ABCDEF); - try test_floateisf(0xBF800000, i256, -1); - try test_floateisf(0x00000000, i256, 0); - try test_floateisf(0x5F012345, i256, 0x8123456789ABCDEF); - try test_floateisf(0x5F012346, i256, 0x8123458000000000); - try test_floateisf(0x5F012346, i256, 0x8123458000000001); - try test_floateisf(0x5F012346, i256, 0x8123458100000000); - try test_floateisf(0x5F012346, i256, 0x8123468000000000); - try test_floateisf(0x5F012347, i256, 0x8123468000000001); - try test_floateisf(0x5F012347, i256, 0x8123468100000000); - try test_floateisf(0x7F000000, i256, math.maxInt(u127)); - try test_floateisf(0x7F000000, i256, 1 << 127); +test f32_floatFromInt_signed { + try test_f32_floatFromInt(0xFF000000, i256, -1 << 127); + try test_f32_floatFromInt(0xFF000000, i256, -math.maxInt(u127)); + try test_f32_floatFromInt(0xDF012347, i256, -0x8123468100000000); + try test_f32_floatFromInt(0xDF012347, i256, -0x8123468000000001); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123468000000000); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458100000000); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458000000001); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458000000000); + try test_f32_floatFromInt(0xDF012345, i256, -0x8123456789ABCDEF); + try test_f32_floatFromInt(0xBF800000, i256, -1); + try test_f32_floatFromInt(0x00000000, i256, 0); + try test_f32_floatFromInt(0x5F012345, i256, 0x8123456789ABCDEF); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458000000000); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458000000001); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458100000000); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123468000000000); + try test_f32_floatFromInt(0x5F012347, i256, 0x8123468000000001); + try test_f32_floatFromInt(0x5F012347, i256, 0x8123468100000000); + try test_f32_floatFromInt(0x7F000000, i256, math.maxInt(u127)); + try test_f32_floatFromInt(0x7F000000, i256, 1 << 127); } -test "floatuneisf" { - try test_floateisf(0x00000000, u256, 0); - try test_floateisf(0x5F012345, u256, 0x8123456789ABCDEF); - try test_floateisf(0x5F012346, u256, 0x8123458000000000); - try test_floateisf(0x5F012346, u256, 0x8123458000000001); - try test_floateisf(0x5F012346, u256, 0x8123458080000000); - try test_floateisf(0x5F012346, u256, 0x8123468000000000); - try test_floateisf(0x5F012347, u256, 0x8123468000000001); - try test_floateisf(0x5F012347, u256, 0x8123468080000000); - try test_floateisf(0x7F000000, u256, math.maxInt(u127)); - try test_floateisf(0x7F000000, u256, 1 << 127); - try test_floateisf(0x7F800000, u256, math.maxInt(u256)); +test f32_floatFromInt_unsigned { + try test_f32_floatFromInt(0x00000000, u256, 0); + try test_f32_floatFromInt(0x5F012345, u256, 0x8123456789ABCDEF); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458000000000); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458000000001); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458080000000); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123468000000000); + try test_f32_floatFromInt(0x5F012347, u256, 0x8123468000000001); + try test_f32_floatFromInt(0x5F012347, u256, 0x8123468080000000); + try test_f32_floatFromInt(0x7F000000, u256, math.maxInt(u127)); + try test_f32_floatFromInt(0x7F000000, u256, 1 << 127); + try test_f32_floatFromInt(0x7F800000, u256, math.maxInt(u256)); } -fn test_one_floatsidf(a: i32, expected: u64) !void { - const r = __floatsidf(a); +fn test_f64_floatFromInt_i32(a: i32, expected: u64) !void { + const r = f64_floatFromInt_i32(a); try std.testing.expect(@as(u64, @bitCast(r)) == expected); } -fn test_one_floatunsidf(a: u32, expected: u64) !void { - const r = __floatunsidf(a); +fn test_f64_floatFromInt_u32(a: u32, expected: u64) !void { + const r = f64_floatFromInt_u32(a); try std.testing.expect(@as(u64, @bitCast(r)) == expected); } -test "floatsidf" { - try test_one_floatsidf(0, 0x0000000000000000); - try test_one_floatsidf(1, 0x3ff0000000000000); - try test_one_floatsidf(-1, 0xbff0000000000000); - try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatsidf(@bitCast(@as(u32, @intCast(0x80000000))), 0xc1e0000000000000); +test f64_floatFromInt_i32 { + try test_f64_floatFromInt_i32(0, 0x0000000000000000); + try test_f64_floatFromInt_i32(1, 0x3ff0000000000000); + try test_f64_floatFromInt_i32(-1, 0xbff0000000000000); + try test_f64_floatFromInt_i32(0x7FFFFFFF, 0x41dfffffffc00000); + try test_f64_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xc1e0000000000000); } -test "floatunsidf" { - try test_one_floatunsidf(0, 0x0000000000000000); - try test_one_floatunsidf(1, 0x3ff0000000000000); - try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatunsidf(@intCast(0x80000000), 0x41e0000000000000); - try test_one_floatunsidf(@intCast(0xFFFFFFFF), 0x41efffffffe00000); +test f64_floatFromInt_u32 { + try test_f64_floatFromInt_u32(0, 0x0000000000000000); + try test_f64_floatFromInt_u32(1, 0x3ff0000000000000); + try test_f64_floatFromInt_u32(0x7FFFFFFF, 0x41dfffffffc00000); + try test_f64_floatFromInt_u32(@intCast(0x80000000), 0x41e0000000000000); + try test_f64_floatFromInt_u32(@intCast(0xFFFFFFFF), 0x41efffffffe00000); } -fn test__floatdidf(a: i64, expected: f64) !void { - const r = __floatdidf(a); +fn test_f64_floatFromInt_i64(a: i64, expected: f64) !void { + const r = f64_floatFromInt_i64(a); try testing.expect(r == expected); } -fn test__floatundidf(a: u64, expected: f64) !void { - const r = __floatundidf(a); +fn test_f64_floatFromInt_u64(a: u64, expected: f64) !void { + const r = f64_floatFromInt_u64(a); try testing.expect(r == expected); } -test "floatdidf" { - try test__floatdidf(0, 0.0); - try test__floatdidf(1, 1.0); - try test__floatdidf(2, 2.0); - try test__floatdidf(20, 20.0); - try test__floatdidf(-1, -1.0); - try test__floatdidf(-2, -2.0); - try test__floatdidf(-20, -20.0); - try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000008000000000))), -0x1.FFFFFEp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000800))), -0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000010000000000))), -0x1.FFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000001000))), -0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000000))), -0x1.000000p+63); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000001))), -0x1.000000p+63); // 0x8000000000000001 - try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +test f64_floatFromInt_i64 { + try test_f64_floatFromInt_i64(0, 0.0); + try test_f64_floatFromInt_i64(1, 1.0); + try test_f64_floatFromInt_i64(2, 2.0); + try test_f64_floatFromInt_i64(20, 20.0); + try test_f64_floatFromInt_i64(-1, -1.0); + try test_f64_floatFromInt_i64(-2, -2.0); + try test_f64_floatFromInt_i64(-20, -20.0); + try test_f64_floatFromInt_i64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_i64(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_i64(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000008000000000))), -0x1.FFFFFEp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000800))), -0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000010000000000))), -0x1.FFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000001000))), -0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000000))), -0x1.000000p+63); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000001))), -0x1.000000p+63); // 0x8000000000000001 + try test_f64_floatFromInt_i64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f64_floatFromInt_i64(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_i64(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_i64(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_i64(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_i64(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test_f64_floatFromInt_i64(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_i64(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_i64(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_i64(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_i64(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f64_floatFromInt_i64(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); } -test "floatundidf" { - try test__floatundidf(0, 0.0); - try test__floatundidf(1, 1.0); - try test__floatundidf(2, 2.0); - try test__floatundidf(20, 20.0); - try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatundidf(0x8000008000000000, 0x1.000001p+63); - try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63); - try test__floatundidf(0x8000010000000000, 0x1.000002p+63); - try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63); - try test__floatundidf(0x8000000000000000, 0x1p+63); - try test__floatundidf(0x8000000000000001, 0x1p+63); - try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +test f64_floatFromInt_u64 { + try test_f64_floatFromInt_u64(0, 0.0); + try test_f64_floatFromInt_u64(1, 1.0); + try test_f64_floatFromInt_u64(2, 2.0); + try test_f64_floatFromInt_u64(20, 20.0); + try test_f64_floatFromInt_u64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_u64(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_u64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_u64(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_u64(0x8000008000000000, 0x1.000001p+63); + try test_f64_floatFromInt_u64(0x8000000000000800, 0x1.0000000000001p+63); + try test_f64_floatFromInt_u64(0x8000010000000000, 0x1.000002p+63); + try test_f64_floatFromInt_u64(0x8000000000001000, 0x1.0000000000002p+63); + try test_f64_floatFromInt_u64(0x8000000000000000, 0x1p+63); + try test_f64_floatFromInt_u64(0x8000000000000001, 0x1p+63); + try test_f64_floatFromInt_u64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f64_floatFromInt_u64(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_u64(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_u64(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_u64(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_u64(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test_f64_floatFromInt_u64(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_u64(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_u64(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_u64(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_u64(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f64_floatFromInt_u64(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); } -fn test__floattidf(a: i128, expected: f64) !void { - const x = __floattidf(a); +fn test_f64_floatFromInt_i128(a: i128, expected: f64) !void { + const x = f64_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntidf(a: u128, expected: f64) !void { - const x = __floatuntidf(a); +fn test_f64_floatFromInt_u128(a: u128, expected: f64) !void { + const x = f64_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattidf" { - try test__floattidf(0, 0.0); - - try test__floattidf(1, 1.0); - try test__floattidf(2, 2.0); - try test__floattidf(20, 20.0); - try test__floattidf(-1, -1.0); - try test__floattidf(-2, -2.0); - try test__floattidf(-20, -20.0); - - try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127); - - try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +test f64_floatFromInt_i128 { + try test_f64_floatFromInt_i128(0, 0.0); + + try test_f64_floatFromInt_i128(1, 1.0); + try test_f64_floatFromInt_i128(2, 2.0); + try test_f64_floatFromInt_i128(20, 20.0); + try test_f64_floatFromInt_i128(-1, -1.0); + try test_f64_floatFromInt_i128(-2, -2.0); + try test_f64_floatFromInt_i128(-20, -20.0); + + try test_f64_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_i128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_i128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f64_floatFromInt_i128(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test_f64_floatFromInt_i128(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test_f64_floatFromInt_i128(make_ti(0x8000000000000001, 0), -0x1.000000p+127); + + try test_f64_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f64_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f64_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f64_floatFromInt_i128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); } -test "floatuntidf" { - try test__floatuntidf(0, 0.0); - - try test__floatuntidf(1, 1.0); - try test__floatuntidf(2, 2.0); - try test__floatuntidf(20, 20.0); - - try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floatuntidf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntidf(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); - try test__floatuntidf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - try test__floatuntidf(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); - - try test__floatuntidf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - try test__floatuntidf(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); - - try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntidf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +test f64_floatFromInt_u128 { + try test_f64_floatFromInt_u128(0, 0.0); + + try test_f64_floatFromInt_u128(1, 1.0); + try test_f64_floatFromInt_u128(2, 2.0); + try test_f64_floatFromInt_u128(20, 20.0); + + try test_f64_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_u128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_u128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f64_floatFromInt_u128(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); + + try test_f64_floatFromInt_u128(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); + + try test_f64_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f64_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f64_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f64_floatFromInt_u128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); } -fn test__floatsitf(a: i32, expected: u128) !void { - const r = __floatsitf(a); +fn test_f128_floatFromInt_i32(a: i32, expected: u128) !void { + const r = f128_floatFromInt_i32(a); try std.testing.expect(@as(u128, @bitCast(r)) == expected); } -test "floatsitf" { - try test__floatsitf(0, 0); - try test__floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); - try test__floatsitf(0x12345678, 0x401b2345678000000000000000000000); - try test__floatsitf(-0x12345678, 0xc01b2345678000000000000000000000); - try test__floatsitf(@bitCast(@as(u32, @intCast(0xffffffff))), 0xbfff0000000000000000000000000000); - try test__floatsitf(@bitCast(@as(u32, @intCast(0x80000000))), 0xc01e0000000000000000000000000000); -} - -fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunsitf(a); +fn test_f128_floatFromInt_u32(a: u32, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatFromInt_u32(a); const x_repr: u128 = @bitCast(x); const x_hi: u64 = @intCast(x_repr >> 64); @@ -581,24 +603,32 @@ fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { return; } } + return error.TestFailure; +} - @panic("__floatunsitf test failure"); +test f128_floatFromInt_i32 { + try test_f128_floatFromInt_i32(0, 0); + try test_f128_floatFromInt_i32(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); + try test_f128_floatFromInt_i32(0x12345678, 0x401b2345678000000000000000000000); + try test_f128_floatFromInt_i32(-0x12345678, 0xc01b2345678000000000000000000000); + try test_f128_floatFromInt_i32(@bitCast(@as(u32, @intCast(0xffffffff))), 0xbfff0000000000000000000000000000); + try test_f128_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xc01e0000000000000000000000000000); } -test "floatunsitf" { - try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0); - try test__floatunsitf(0, 0x0, 0x0); - try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0); - try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0); +test f128_floatFromInt_u32 { + try test_f128_floatFromInt_u32(0x7fffffff, 0x401dfffffffc0000, 0x0); + try test_f128_floatFromInt_u32(0, 0x0, 0x0); + try test_f128_floatFromInt_u32(0xffffffff, 0x401efffffffe0000, 0x0); + try test_f128_floatFromInt_u32(0x12345678, 0x401b234567800000, 0x0); } -fn test__floatditf(a: i64, expected: f128) !void { - const x = __floatditf(a); +fn test_f128_floatFromInt_i64(a: i64, expected: f128) !void { + const x = f128_floatFromInt_i64(a); try testing.expect(x == expected); } -fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunditf(a); +fn test_f128_floatFromInt_u64(a: u64, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatFromInt_u64(a); const x_repr: u128 = @bitCast(x); const x_hi: u64 = @intCast(x_repr >> 64); @@ -613,208 +643,207 @@ fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { return; } } - - @panic("__floatunditf test failure"); + return error.TestFailure; } -test "floatditf" { - try test__floatditf(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); - try test__floatditf(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); - try test__floatditf(0x2, make_tf(0x4000000000000000, 0x0)); - try test__floatditf(0x1, make_tf(0x3fff000000000000, 0x0)); - try test__floatditf(0x0, make_tf(0x0, 0x0)); - try test__floatditf(@bitCast(@as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); - try test__floatditf(@bitCast(@as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); - try test__floatditf(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); - try test__floatditf(@bitCast(@as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); +test f128_floatFromInt_i64 { + try test_f128_floatFromInt_i64(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); + try test_f128_floatFromInt_i64(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); + try test_f128_floatFromInt_i64(0x2, make_tf(0x4000000000000000, 0x0)); + try test_f128_floatFromInt_i64(0x1, make_tf(0x3fff000000000000, 0x0)); + try test_f128_floatFromInt_i64(0x0, make_tf(0x0, 0x0)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); + try test_f128_floatFromInt_i64(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); } -test "floatunditf" { - try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); - try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); - try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0); - try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); - try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); - try test__floatunditf(0x2, 0x4000000000000000, 0x0); - try test__floatunditf(0x1, 0x3fff000000000000, 0x0); - try test__floatunditf(0x0, 0x0, 0x0); +test f128_floatFromInt_u64 { + try test_f128_floatFromInt_u64(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); + try test_f128_floatFromInt_u64(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); + try test_f128_floatFromInt_u64(0x8000000000000000, 0x403e000000000000, 0x0); + try test_f128_floatFromInt_u64(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); + try test_f128_floatFromInt_u64(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); + try test_f128_floatFromInt_u64(0x2, 0x4000000000000000, 0x0); + try test_f128_floatFromInt_u64(0x1, 0x3fff000000000000, 0x0); + try test_f128_floatFromInt_u64(0x0, 0x0, 0x0); } -fn test__floattitf(a: i128, expected: f128) !void { - const x = __floattitf(a); +fn test_f128_floatFromInt_i128(a: i128, expected: f128) !void { + const x = f128_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntitf(a: u128, expected: f128) !void { - const x = __floatuntitf(a); +fn test_f128_floatFromInt_u128(a: u128, expected: f128) !void { + const x = f128_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattitf" { - try test__floattitf(0, 0.0); - - try test__floattitf(1, 1.0); - try test__floattitf(2, 2.0); - try test__floattitf(20, 20.0); - try test__floattitf(-1, -1.0); - try test__floattitf(-2, -2.0); - try test__floattitf(-20, -20.0); - - try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); - - try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +test f128_floatFromInt_i128 { + try test_f128_floatFromInt_i128(0, 0.0); + + try test_f128_floatFromInt_i128(1, 1.0); + try test_f128_floatFromInt_i128(2, 2.0); + try test_f128_floatFromInt_i128(20, 20.0); + try test_f128_floatFromInt_i128(-1, -1.0); + try test_f128_floatFromInt_i128(-2, -2.0); + try test_f128_floatFromInt_i128(-20, -20.0); + + try test_f128_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f128_floatFromInt_i128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f128_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f128_floatFromInt_i128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f128_floatFromInt_i128(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test_f128_floatFromInt_i128(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test_f128_floatFromInt_i128(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); + + try test_f128_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f128_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f128_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f128_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f128_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f128_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f128_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f128_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f128_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f128_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f128_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f128_floatFromInt_i128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test_f128_floatFromInt_i128(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); } -test "floatuntitf" { - try test__floatuntitf(0, 0.0); - - try test__floatuntitf(1, 1.0); - try test__floatuntitf(2, 2.0); - try test__floatuntitf(20, 20.0); - - try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); - try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); - try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); - - try test__floatuntitf(0x8000008000000000, 0x8.000008p+60); - try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60); - try test__floatuntitf(0x8000010000000000, 0x8.00001p+60); - try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60); - - try test__floatuntitf(0x8000000000000000, 0x8p+60); - try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60); - - try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntitf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntitf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floatuntitf(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); - - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +test f128_floatFromInt_u128 { + try test_f128_floatFromInt_u128(0, 0.0); + + try test_f128_floatFromInt_u128(1, 1.0); + try test_f128_floatFromInt_u128(2, 2.0); + try test_f128_floatFromInt_u128(20, 20.0); + + try test_f128_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f128_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); + try test_f128_floatFromInt_u128(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); + try test_f128_floatFromInt_u128(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); + + try test_f128_floatFromInt_u128(0x8000008000000000, 0x8.000008p+60); + try test_f128_floatFromInt_u128(0x8000000000000800, 0x8.0000000000008p+60); + try test_f128_floatFromInt_u128(0x8000010000000000, 0x8.00001p+60); + try test_f128_floatFromInt_u128(0x8000000000001000, 0x8.000000000001p+60); + + try test_f128_floatFromInt_u128(0x8000000000000000, 0x8p+60); + try test_f128_floatFromInt_u128(0x8000000000000001, 0x8.000000000000001p+60); + + try test_f128_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f128_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f128_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f128_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f128_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f128_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f128_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f128_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f128_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f128_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f128_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f128_floatFromInt_u128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test_f128_floatFromInt_u128(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test_f128_floatFromInt_u128(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); + try test_f128_floatFromInt_u128(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); + + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); } fn make_ti(high: u64, low: u64) i128 { @@ -838,45 +867,40 @@ fn make_tf(high: u64, low: u64) f128 { return @bitCast(result); } -test "conversion to f16" { - try testing.expect(__floatunsihf(@as(u32, 0)) == 0.0); - try testing.expect(__floatunsihf(@as(u32, 1)) == 1.0); - try testing.expect(__floatunsihf(@as(u32, 65504)) == 65504); - try testing.expect(__floatunsihf(@as(u32, 65504 + (1 << 4))) == math.inf(f16)); +test f16_floatFromInt_u32 { + try testing.expect(f16_floatFromInt_u32(0) == 0.0); + try testing.expect(f16_floatFromInt_u32(1) == 1.0); + try testing.expect(f16_floatFromInt_u32(65504) == 65504); + try testing.expect(f16_floatFromInt_u32(65504 + (1 << 4)) == math.inf(f16)); } -test "conversion to f32" { - try testing.expect(__floatunsisf(@as(u32, 0)) == 0.0); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u32))) != 1.0); - try testing.expect(__floatsisf(@as(i32, math.minInt(i32))) != 1.0); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24))) == math.maxInt(u24)); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact +test f80_floatFromInt_u32 { + try testing.expect(f80_floatFromInt_u32(0) == 0.0); + try testing.expect(f80_floatFromInt_u32(1) == 1.0); + try testing.expect(f80_floatFromInt_u32(math.maxInt(u24) + 0) == math.maxInt(u24)); } -test "conversion to f80" { - const floatFromInt = @import("./float_from_int.zig").floatFromInt; +test f80_floatFromInt_u64 { + try testing.expect(f80_floatFromInt_u64(math.maxInt(u64) + 0) == math.maxInt(u64) + 0); +} + +test f80_floatFromInt_i128 { + try testing.expect(f80_floatFromInt_i128(-12) == -12); +} - try testing.expect(floatFromInt(f80, @as(i80, -12)) == -12); - try testing.expect(@as(u80, @intFromFloat(floatFromInt(f80, @as(u64, math.maxInt(u64)) + 0))) == math.maxInt(u64) + 0); - try testing.expect(@as(u80, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 1))) == math.maxInt(u64) + 1); +test f80_floatFromInt_u128 { + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 1) == math.maxInt(u64) + 1); - try testing.expect(floatFromInt(f80, @as(u32, 0)) == 0.0); - try testing.expect(floatFromInt(f80, @as(u32, 1)) == 1.0); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u32, math.maxInt(u24)) + 0))) == math.maxInt(u24)); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 0))) == math.maxInt(u64)); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 1))) == math.maxInt(u64) + 1); // Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 2))) == math.maxInt(u64) + 1); // Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 3))) == math.maxInt(u64) + 3); // Tie - Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 4))) == math.maxInt(u64) + 5); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 0) == math.maxInt(u64)); + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 1) == math.maxInt(u64) + 1); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 2) == math.maxInt(u64) + 1); // Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 3) == math.maxInt(u64) + 3); // Tie - Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 4) == math.maxInt(u64) + 5); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 0))) == math.maxInt(u65) + 1); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 1))) == math.maxInt(u65) + 1); // Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 2))) == math.maxInt(u65) + 1); // Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 3))) == math.maxInt(u65) + 1); // Tie - Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 4))) == math.maxInt(u65) + 5); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 5))) == math.maxInt(u65) + 5); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 0) == math.maxInt(u65) + 1); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 1) == math.maxInt(u65) + 1); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 2) == math.maxInt(u65) + 1); // Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 3) == math.maxInt(u65) + 1); // Tie - Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 4) == math.maxInt(u65) + 5); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 5) == math.maxInt(u65) + 5); // Exact } diff --git a/lib/compiler_rt/floatdidf.zig b/lib/compiler_rt/floatdidf.zig deleted file mode 100644 index f8d5153d5b43896b3dd26a32e84f613151b84653..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdidf.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_l2d, "__aeabi_l2d"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatdidf, "__i64tod"); - } - symbol(&__floatdidf, "__floatdidf"); - } -} - -pub fn __floatdidf(a: i64) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_l2d(a: i64) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatdihf.zig b/lib/compiler_rt/floatdihf.zig deleted file mode 100644 index c6865dff6b8025e49b8f1a0ffc36674c230247a4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdihf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatdihf, "__floatdihf"); -} - -fn __floatdihf(a: i64) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatdisf.zig b/lib/compiler_rt/floatdisf.zig deleted file mode 100644 index 3da1faba367a6a17b81f97c93db6ff2041765b84..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdisf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_l2f, "__aeabi_l2f"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatdisf, "__i64tos"); - } - symbol(&__floatdisf, "__floatdisf"); - } -} - -pub fn __floatdisf(a: i64) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_l2f(a: i64) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatditf.zig b/lib/compiler_rt/floatditf.zig deleted file mode 100644 index 033c35ffcbdd2137d84890c9176d7c77fe29541e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatditf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatditf, "__floatdikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_xtoq, "_Qp_xtoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatditf, "_Q_lltoq"); - } - symbol(&__floatditf, "__floatditf"); -} - -pub fn __floatditf(a: i64) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_xtoq(c: *f128, a: i64) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatdixf.zig b/lib/compiler_rt/floatdixf.zig deleted file mode 100644 index 6bd06245d584402e7ed93b0d57d71f471bde05d4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdixf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatdixf, "__floatdixf"); -} - -fn __floatdixf(a: i64) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floateidf.zig b/lib/compiler_rt/floateidf.zig deleted file mode 100644 index ac3972c28778600d342d0412741e9a3e41797546..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateidf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floateidf, "__floateidf"); -} - -pub fn __floateidf(a: [*]const u8, bits: usize) callconv(.c) f64 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f64, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateihf.zig b/lib/compiler_rt/floateihf.zig deleted file mode 100644 index c1ec290fb1084a05b6353ffde4968bce3c3cd3d8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateihf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateihf, "__floateihf"); -} - -pub fn __floateihf(a: [*]const u8, bits: usize) callconv(.c) f16 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f16, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateisf.zig b/lib/compiler_rt/floateisf.zig deleted file mode 100644 index dd5933b7dff321ee90d0b13ee6d9a5e0d85a9f20..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateisf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateisf, "__floateisf"); -} - -pub fn __floateisf(a: [*]const u8, bits: usize) callconv(.c) f32 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f32, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateitf.zig b/lib/compiler_rt/floateitf.zig deleted file mode 100644 index 0df893bd18881c9ec382e718a7664bf4d0f7a8e4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateitf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateitf, "__floateitf"); -} - -pub fn __floateitf(a: [*]const u8, bits: usize) callconv(.c) f128 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f128, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateixf.zig b/lib/compiler_rt/floateixf.zig deleted file mode 100644 index dafefa4e8f11b978f26b5e4d10cc8b0feeed480b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateixf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateixf, "__floateixf"); -} - -pub fn __floateixf(a: [*]const u8, bits: usize) callconv(.c) f80 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f80, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatsidf.zig b/lib/compiler_rt/floatsidf.zig deleted file mode 100644 index dc5a261a08f1e86155d7af20b62b43b02c99bbe5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsidf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_i2d, "__aeabi_i2d"); - } else { - symbol(&__floatsidf, "__floatsidf"); - } -} - -pub fn __floatsidf(a: i32) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_i2d(a: i32) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatsihf.zig b/lib/compiler_rt/floatsihf.zig deleted file mode 100644 index e1d588cfb0da1ed1007496f3d32db0fcdd8612ef..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatsihf, "__floatsihf"); -} - -fn __floatsihf(a: i32) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatsisf.zig b/lib/compiler_rt/floatsisf.zig deleted file mode 100644 index 0dac860ebfded913a3eacb1666cb34e246f87dde..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsisf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_i2f, "__aeabi_i2f"); - } else { - symbol(&__floatsisf, "__floatsisf"); - } -} - -pub fn __floatsisf(a: i32) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_i2f(a: i32) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatsitf.zig b/lib/compiler_rt/floatsitf.zig deleted file mode 100644 index 865ebce60fddaa5d8234cf76293b08e12be30000..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsitf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatsitf, "__floatsikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_itoq, "_Qp_itoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatsitf, "_Q_itoq"); - } - symbol(&__floatsitf, "__floatsitf"); -} - -pub fn __floatsitf(a: i32) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_itoq(c: *f128, a: i32) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatsixf.zig b/lib/compiler_rt/floatsixf.zig deleted file mode 100644 index bd28eaf1fa68f9580f63b918bfeea6cc78295699..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floatsixf, "__floatsixf"); -} - -fn __floatsixf(a: i32) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floattidf.zig b/lib/compiler_rt/floattidf.zig deleted file mode 100644 index 02298705324edcd49b36f69a64c0c78873ecb57b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattidf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattidf, "__floattidf"); -} - -pub fn __floattidf(a: i128) callconv(.c) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floattihf.zig b/lib/compiler_rt/floattihf.zig deleted file mode 100644 index a751e3142c5b273819199105a6848c0280aee3c5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattihf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattihf, "__floattihf"); -} - -pub fn __floattihf(a: i128) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floattisf.zig b/lib/compiler_rt/floattisf.zig deleted file mode 100644 index 72af61c6b6805d9bd03e6d215dd300fe7589c21f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattisf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floattisf, "__floattisf"); -} - -pub fn __floattisf(a: i128) callconv(.c) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floattitf.zig b/lib/compiler_rt/floattitf.zig deleted file mode 100644 index 3e49a68fd56912ebe7573346b6b8aea6b98b91ba..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattitf.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__floattitf, "__floattikf"); - symbol(&__floattitf, "__floattitf"); -} - -pub fn __floattitf(a: i128) callconv(.c) f128 { - return floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floattixf.zig b/lib/compiler_rt/floattixf.zig deleted file mode 100644 index be05180795aef517800c15d01c928bab4f7f19a0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattixf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattixf, "__floattixf"); -} - -pub fn __floattixf(a: i128) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatundidf.zig b/lib/compiler_rt/floatundidf.zig deleted file mode 100644 index 852675370503bab154245fd685ff2c2a5449aea0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundidf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ul2d, "__aeabi_ul2d"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatundidf, "__u64tod"); - } - symbol(&__floatundidf, "__floatundidf"); - } -} - -pub fn __floatundidf(a: u64) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_ul2d(a: u64) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatundihf.zig b/lib/compiler_rt/floatundihf.zig deleted file mode 100644 index 064d565d2dc4ec4f118dee8400375de802400f2b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatundihf, "__floatundihf"); -} - -fn __floatundihf(a: u64) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatundisf.zig b/lib/compiler_rt/floatundisf.zig deleted file mode 100644 index 827a419fd5315624866af773ea71a9098b2bcb3e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundisf.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ul2f, "__aeabi_ul2f"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatundisf, "__u64tos"); - } - symbol(&__floatundisf, "__floatundisf"); - } -} - -pub fn __floatundisf(a: u64) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_ul2f(a: u64) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatunditf.zig b/lib/compiler_rt/floatunditf.zig deleted file mode 100644 index 79f9f54e176f5741bbc901b1790895feaadf1f98..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunditf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatunditf, "__floatundikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_uxtoq, "_Qp_uxtoq"); - } else if (compiler_rt.want_sparc32_abi) { - @export(&__floatunditf, "_Q_ulltoq"); - } - symbol(&__floatunditf, "__floatunditf"); -} - -pub fn __floatunditf(a: u64) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_uxtoq(c: *f128, a: u64) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatundixf.zig b/lib/compiler_rt/floatundixf.zig deleted file mode 100644 index ce36d47a4ef225c67e4e45f3695cdb14649cee4c..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatundixf, "__floatundixf"); -} - -fn __floatundixf(a: u64) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatuneidf.zig b/lib/compiler_rt/floatuneidf.zig deleted file mode 100644 index 6e391b7cf1c4baeacb55c731ca24c66750c6d346..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneidf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneidf, "__floatuneidf"); -} - -pub fn __floatuneidf(a: [*]const u8, bits: usize) callconv(.c) f64 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f64, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneihf.zig b/lib/compiler_rt/floatuneihf.zig deleted file mode 100644 index 0df0cf155be8e7d39afb5012940fa85ec3211603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneihf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneihf, "__floatuneihf"); -} - -pub fn __floatuneihf(a: [*]const u8, bits: usize) callconv(.c) f16 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f16, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneisf.zig b/lib/compiler_rt/floatuneisf.zig deleted file mode 100644 index e2dadd9ffddc6efe13ffd53bb9f2cdeeffc3530d..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneisf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneisf, "__floatuneisf"); -} - -pub fn __floatuneisf(a: [*]const u8, bits: usize) callconv(.c) f32 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f32, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneitf.zig b/lib/compiler_rt/floatuneitf.zig deleted file mode 100644 index ddee65dfb18b793bffe08d850384842fcff5747e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneitf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneitf, "__floatuneitf"); -} - -pub fn __floatuneitf(a: [*]const u8, bits: usize) callconv(.c) f128 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f128, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneixf.zig b/lib/compiler_rt/floatuneixf.zig deleted file mode 100644 index 75dd565daffe16ffb4e95230266fca2f5d288603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneixf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneixf, "__floatuneixf"); -} - -pub fn __floatuneixf(a: [*]const u8, bits: usize) callconv(.c) f80 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f80, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatunsidf.zig b/lib/compiler_rt/floatunsidf.zig deleted file mode 100644 index 94949c7bff4eafff900a0b22e53998a930c3d7ea..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsidf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ui2d, "__aeabi_ui2d"); - } else { - symbol(&__floatunsidf, "__floatunsidf"); - } -} - -pub fn __floatunsidf(a: u32) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_ui2d(a: u32) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatunsihf.zig b/lib/compiler_rt/floatunsihf.zig deleted file mode 100644 index a2e42ca10f3af950e900f5250fa6a3d23e2b1266..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsihf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatunsihf, "__floatunsihf"); -} - -pub fn __floatunsihf(a: u32) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatunsisf.zig b/lib/compiler_rt/floatunsisf.zig deleted file mode 100644 index 04da1aa5c03cf76815cccf2273731501d1c8edc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsisf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ui2f, "__aeabi_ui2f"); - } else { - symbol(&__floatunsisf, "__floatunsisf"); - } -} - -pub fn __floatunsisf(a: u32) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_ui2f(a: u32) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatunsitf.zig b/lib/compiler_rt/floatunsitf.zig deleted file mode 100644 index 2b7c58eab8bd7c2a238062e0cc123f5ce6b8c9e0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsitf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatunsitf, "__floatunsikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_uitoq, "_Qp_uitoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatunsitf, "_Q_utoq"); - } - symbol(&__floatunsitf, "__floatunsitf"); -} - -pub fn __floatunsitf(a: u32) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_uitoq(c: *f128, a: u32) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatunsixf.zig b/lib/compiler_rt/floatunsixf.zig deleted file mode 100644 index 906f0270f5c53d28970a0c250b24abcadfa72946..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatunsixf, "__floatunsixf"); -} - -fn __floatunsixf(a: u32) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatuntidf.zig b/lib/compiler_rt/floatuntidf.zig deleted file mode 100644 index b770457bc4992a5bd6237d832e2ca4c0cbed11e0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntidf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floatuntidf, "__floatuntidf"); -} - -pub fn __floatuntidf(a: u128) callconv(.c) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatuntihf.zig b/lib/compiler_rt/floatuntihf.zig deleted file mode 100644 index 5b4373cb7c496b0acf1a2fe6ef988872b30e8780..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntihf, "__floatuntihf"); -} - -pub fn __floatuntihf(a: u128) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatuntisf.zig b/lib/compiler_rt/floatuntisf.zig deleted file mode 100644 index de9a021476edecfcc26761133c0645d799c677da..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntisf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntisf, "__floatuntisf"); -} - -pub fn __floatuntisf(a: u128) callconv(.c) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatuntitf.zig b/lib/compiler_rt/floatuntitf.zig deleted file mode 100644 index 47cd65cc3ff4460d937e0ccd7acabb2455ae704a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntitf.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__floatuntitf, "__floatuntikf"); - symbol(&__floatuntitf, "__floatuntitf"); -} - -pub fn __floatuntitf(a: u128) callconv(.c) f128 { - return floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatuntixf.zig b/lib/compiler_rt/floatuntixf.zig deleted file mode 100644 index 41fb45b3a3a1b8e213c03a4ef5e847feb8d31211..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntixf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntixf, "__floatuntixf"); -} - -pub fn __floatuntixf(a: u128) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floor_ceil.zig b/lib/compiler_rt/floor_ceil.zig index f81d2e0011286a1ea45a3ef147fc704eadac4b4e..8bd82275e3787ae52587eb84c1391ee5949f616b 100644 --- a/lib/compiler_rt/floor_ceil.zig +++ b/lib/compiler_rt/floor_ceil.zig @@ -15,7 +15,7 @@ const mem = std.mem; const expect = std.testing.expect; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { // floor @@ -23,10 +23,7 @@ comptime { symbol(&floorf, "floorf"); symbol(&floor, "floor"); symbol(&__floorx, "__floorx"); - if (compiler_rt.want_ppc_abi) { - symbol(&floorq, "floorf128"); - } - symbol(&floorq, "floorq"); + symbol(&floorq, "floorf128"); symbol(&floorl, "floorl"); // ceil @@ -34,59 +31,96 @@ comptime { symbol(&ceilf, "ceilf"); symbol(&ceil, "ceil"); symbol(&__ceilx, "__ceilx"); - if (compiler_rt.want_ppc_abi) { - symbol(&ceilq, "ceilf128"); - } - symbol(&ceilq, "ceilq"); + symbol(&ceilq, "ceilf128"); symbol(&ceill, "ceill"); } -pub fn __floorh(x: f16) callconv(.c) f16 { +fn __floorh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(floor_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn floor_f16(x: f16) f16 { return impl(f16, .floor, x); } -pub fn floorf(x: f32) callconv(.c) f32 { +fn floorf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(floor_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn floor_f32(x: f32) f32 { return impl(f32, .floor, x); } -pub fn floor(x: f64) callconv(.c) f64 { +fn floor(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(floor_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn floor_f64(x: f64) f64 { return impl(f64, .floor, x); } -pub fn __floorx(x: f80) callconv(.c) f80 { +fn __floorx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(floor_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn floor_f80(x: f80) f80 { return impl(f80, .floor, x); } -pub fn floorq(x: f128) callconv(.c) f128 { +fn floorq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(floor_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn floor_f128(x: f128) f128 { return impl(f128, .floor, x); } pub fn floorl(x: c_longdouble) callconv(.c) c_longdouble { - return impl(std.meta.Float(@bitSizeOf(c_longdouble)), .floor, x); + switch (@typeInfo(c_longdouble).float.bits) { + 64 => return floor_f64(x), + 80 => return floor_f80(x), + 128 => return floor_f128(x), + else => comptime unreachable, + } } -pub fn __ceilh(x: f16) callconv(.c) f16 { +fn __ceilh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(ceil_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn ceil_f16(x: f16) f16 { return impl(f16, .ceil, x); } -pub fn ceilf(x: f32) callconv(.c) f32 { +fn ceilf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(ceil_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn ceil_f32(x: f32) f32 { return impl(f32, .ceil, x); } -pub fn ceil(x: f64) callconv(.c) f64 { +fn ceil(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(ceil_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn ceil_f64(x: f64) f64 { return impl(f64, .ceil, x); } -pub fn __ceilx(x: f80) callconv(.c) f80 { +fn __ceilx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(ceil_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn ceil_f80(x: f80) f80 { return impl(f80, .ceil, x); } -pub fn ceilq(x: f128) callconv(.c) f128 { +fn ceilq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(ceil_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn ceil_f128(x: f128) f128 { return impl(f128, .ceil, x); } pub fn ceill(x: c_longdouble) callconv(.c) c_longdouble { - return impl(std.meta.Float(@bitSizeOf(c_longdouble)), .ceil, x); + switch (@typeInfo(c_longdouble).float.bits) { + 64 => return ceil_f64(x), + 80 => return ceil_f80(x), + 128 => return ceil_f128(x), + else => comptime unreachable, + } } inline fn impl(comptime T: type, comptime op: enum { floor, ceil }, x: T) T { @@ -144,142 +178,122 @@ inline fn impl(comptime T: type, comptime op: enum { floor, ceil }, x: T) T { } } -test "floor16" { - try expect(__floorh(1.3) == 1.0); - try expect(__floorh(-1.3) == -2.0); - try expect(__floorh(0.2) == 0.0); -} - -test "floor32" { - try expect(floorf(1.3) == 1.0); - try expect(floorf(-1.3) == -2.0); - try expect(floorf(0.2) == 0.0); -} - -test "floor64" { - try expect(floor(1.3) == 1.0); - try expect(floor(-1.3) == -2.0); - try expect(floor(0.2) == 0.0); -} - -test "floor80" { - try expect(__floorx(1.3) == 1.0); - try expect(__floorx(-1.3) == -2.0); - try expect(__floorx(0.2) == 0.0); -} - -test "floor128" { - try expect(floorq(1.3) == 1.0); - try expect(floorq(-1.3) == -2.0); - try expect(floorq(0.2) == 0.0); -} - -test "floor16.special" { - try expect(__floorh(0.0) == 0.0); - try expect(__floorh(-0.0) == -0.0); - try expect(math.isPositiveInf(__floorh(math.inf(f16)))); - try expect(math.isNegativeInf(__floorh(-math.inf(f16)))); - try expect(math.isNan(__floorh(math.nan(f16)))); -} - -test "floor32.special" { - try expect(floorf(0.0) == 0.0); - try expect(floorf(-0.0) == -0.0); - try expect(math.isPositiveInf(floorf(math.inf(f32)))); - try expect(math.isNegativeInf(floorf(-math.inf(f32)))); - try expect(math.isNan(floorf(math.nan(f32)))); -} - -test "floor64.special" { - try expect(floor(0.0) == 0.0); - try expect(floor(-0.0) == -0.0); - try expect(math.isPositiveInf(floor(math.inf(f64)))); - try expect(math.isNegativeInf(floor(-math.inf(f64)))); - try expect(math.isNan(floor(math.nan(f64)))); -} - -test "floor80.special" { - try expect(__floorx(0.0) == 0.0); - try expect(__floorx(-0.0) == -0.0); - try expect(math.isPositiveInf(__floorx(math.inf(f80)))); - try expect(math.isNegativeInf(__floorx(-math.inf(f80)))); - try expect(math.isNan(__floorx(math.nan(f80)))); -} - -test "floor128.special" { - try expect(floorq(0.0) == 0.0); - try expect(floorq(-0.0) == -0.0); - try expect(math.isPositiveInf(floorq(math.inf(f128)))); - try expect(math.isNegativeInf(floorq(-math.inf(f128)))); - try expect(math.isNan(floorq(math.nan(f128)))); -} - -test "ceil16" { - try expect(__ceilh(1.3) == 2.0); - try expect(__ceilh(-1.3) == -1.0); - try expect(__ceilh(0.2) == 1.0); -} - -test "ceil32" { - try expect(ceilf(1.3) == 2.0); - try expect(ceilf(-1.3) == -1.0); - try expect(ceilf(0.2) == 1.0); -} - -test "ceil64" { - try expect(ceil(1.3) == 2.0); - try expect(ceil(-1.3) == -1.0); - try expect(ceil(0.2) == 1.0); -} - -test "ceil80" { - try expect(__ceilx(1.3) == 2.0); - try expect(__ceilx(-1.3) == -1.0); - try expect(__ceilx(0.2) == 1.0); -} - -test "ceil128" { - try expect(ceilq(1.3) == 2.0); - try expect(ceilq(-1.3) == -1.0); - try expect(ceilq(0.2) == 1.0); -} - -test "ceil16.special" { - try expect(__ceilh(0.0) == 0.0); - try expect(__ceilh(-0.0) == -0.0); - try expect(math.isPositiveInf(__ceilh(math.inf(f16)))); - try expect(math.isNegativeInf(__ceilh(-math.inf(f16)))); - try expect(math.isNan(__ceilh(math.nan(f16)))); -} - -test "ceil32.special" { - try expect(ceilf(0.0) == 0.0); - try expect(ceilf(-0.0) == -0.0); - try expect(math.isPositiveInf(ceilf(math.inf(f32)))); - try expect(math.isNegativeInf(ceilf(-math.inf(f32)))); - try expect(math.isNan(ceilf(math.nan(f32)))); -} - -test "ceil64.special" { - try expect(ceil(0.0) == 0.0); - try expect(ceil(-0.0) == -0.0); - try expect(math.isPositiveInf(ceil(math.inf(f64)))); - try expect(math.isNegativeInf(ceil(-math.inf(f64)))); - try expect(math.isNan(ceil(math.nan(f64)))); -} - -test "ceil80.special" { - try expect(__ceilx(0.0) == 0.0); - try expect(__ceilx(-0.0) == -0.0); - try expect(math.isPositiveInf(__ceilx(math.inf(f80)))); - try expect(math.isNegativeInf(__ceilx(-math.inf(f80)))); - try expect(math.isNan(__ceilx(math.nan(f80)))); -} - -test "ceil128.special" { - try expect(ceilq(0.0) == 0.0); - try expect(ceilq(-0.0) == -0.0); - try expect(math.isPositiveInf(ceilq(math.inf(f128)))); - try expect(math.isNegativeInf(ceilq(-math.inf(f128)))); - try expect(math.isNan(ceilq(math.nan(f128)))); +test floor_f16 { + try expect(floor_f16(1.3) == 1.0); + try expect(floor_f16(-1.3) == -2.0); + try expect(floor_f16(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f16(0.2))); + try expect(math.isPositiveZero(floor_f16(0.0))); + try expect(math.isNegativeZero(floor_f16(-0.0))); + try expect(math.isPositiveInf(floor_f16(math.inf(f16)))); + try expect(math.isNegativeInf(floor_f16(-math.inf(f16)))); + try expect(math.isNan(floor_f16(math.nan(f16)))); +} + +test floor_f32 { + try expect(floor_f32(1.3) == 1.0); + try expect(floor_f32(-1.3) == -2.0); + try expect(floor_f32(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f32(0.2))); + try expect(math.isPositiveZero(floor_f32(0.0))); + try expect(math.isNegativeZero(floor_f32(-0.0))); + try expect(math.isPositiveInf(floor_f32(math.inf(f32)))); + try expect(math.isNegativeInf(floor_f32(-math.inf(f32)))); + try expect(math.isNan(floor_f32(math.nan(f32)))); +} + +test floor_f64 { + try expect(floor_f64(1.3) == 1.0); + try expect(floor_f64(-1.3) == -2.0); + try expect(floor_f64(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f64(0.2))); + try expect(math.isPositiveZero(floor_f64(0.0))); + try expect(math.isNegativeZero(floor_f64(-0.0))); + try expect(math.isPositiveInf(floor_f64(math.inf(f64)))); + try expect(math.isNegativeInf(floor_f64(-math.inf(f64)))); + try expect(math.isNan(floor_f64(math.nan(f64)))); +} + +test floor_f80 { + try expect(floor_f80(1.3) == 1.0); + try expect(floor_f80(-1.3) == -2.0); + try expect(floor_f80(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f80(0.2))); + try expect(math.isPositiveZero(floor_f80(0.0))); + try expect(math.isNegativeZero(floor_f80(-0.0))); + try expect(math.isPositiveInf(floor_f80(math.inf(f80)))); + try expect(math.isNegativeInf(floor_f80(-math.inf(f80)))); + try expect(math.isNan(floor_f80(math.nan(f80)))); +} + +test floor_f128 { + try expect(floor_f128(1.3) == 1.0); + try expect(floor_f128(-1.3) == -2.0); + try expect(floor_f128(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f128(0.2))); + try expect(math.isPositiveZero(floor_f128(0.0))); + try expect(math.isNegativeZero(floor_f128(-0.0))); + try expect(math.isPositiveInf(floor_f128(math.inf(f128)))); + try expect(math.isNegativeInf(floor_f128(-math.inf(f128)))); + try expect(math.isNan(floor_f128(math.nan(f128)))); +} + +test ceil_f16 { + try expect(ceil_f16(1.3) == 2.0); + try expect(ceil_f16(-1.3) == -1.0); + try expect(ceil_f16(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f16(-0.2))); + try expect(math.isPositiveZero(ceil_f16(0.0))); + try expect(math.isNegativeZero(ceil_f16(-0.0))); + try expect(math.isPositiveInf(ceil_f16(math.inf(f16)))); + try expect(math.isNegativeInf(ceil_f16(-math.inf(f16)))); + try expect(math.isNan(ceil_f16(math.nan(f16)))); +} + +test ceil_f32 { + try expect(ceil_f32(1.3) == 2.0); + try expect(ceil_f32(-1.3) == -1.0); + try expect(ceil_f32(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f32(-0.2))); + try expect(math.isPositiveZero(ceil_f32(0.0))); + try expect(math.isNegativeZero(ceil_f32(-0.0))); + try expect(math.isPositiveInf(ceil_f32(math.inf(f32)))); + try expect(math.isNegativeInf(ceil_f32(-math.inf(f32)))); + try expect(math.isNan(ceil_f32(math.nan(f32)))); +} + +test ceil_f64 { + try expect(ceil_f64(1.3) == 2.0); + try expect(ceil_f64(-1.3) == -1.0); + try expect(ceil_f64(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f64(-0.2))); + try expect(math.isPositiveZero(ceil_f64(0.0))); + try expect(math.isNegativeZero(ceil_f64(-0.0))); + try expect(math.isPositiveInf(ceil_f64(math.inf(f64)))); + try expect(math.isNegativeInf(ceil_f64(-math.inf(f64)))); + try expect(math.isNan(ceil_f64(math.nan(f64)))); +} + +test ceil_f80 { + try expect(ceil_f80(1.3) == 2.0); + try expect(ceil_f80(-1.3) == -1.0); + try expect(ceil_f80(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f80(-0.2))); + try expect(math.isPositiveZero(ceil_f80(0.0))); + try expect(math.isNegativeZero(ceil_f80(-0.0))); + try expect(math.isPositiveInf(ceil_f80(math.inf(f80)))); + try expect(math.isNegativeInf(ceil_f80(-math.inf(f80)))); + try expect(math.isNan(ceil_f80(math.nan(f80)))); +} + +test ceil_f128 { + try expect(ceil_f128(1.3) == 2.0); + try expect(ceil_f128(-1.3) == -1.0); + try expect(ceil_f128(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f128(-0.2))); + try expect(math.isPositiveZero(ceil_f128(0.0))); + try expect(math.isNegativeZero(ceil_f128(-0.0))); + try expect(math.isPositiveInf(ceil_f128(math.inf(f128)))); + try expect(math.isNegativeInf(ceil_f128(-math.inf(f128)))); + try expect(math.isNan(ceil_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/fma.zig b/lib/compiler_rt/fma.zig index 61732585db2ece3fb84c3029293cab41662781d2..97bb57d4aae5aebe74c34925abacdb84f3aeef82 100644 --- a/lib/compiler_rt/fma.zig +++ b/lib/compiler_rt/fma.zig @@ -16,19 +16,22 @@ comptime { symbol(&fmaf, "fmaf"); symbol(&fma, "fma"); symbol(&__fmax, "__fmax"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmaq, "fmaf128"); - } - symbol(&fmaq, "fmaq"); + symbol(&fmaq, "fmaf128"); symbol(&fmal, "fmal"); } -pub fn __fmah(x: f16, y: f16, z: f16) callconv(.c) f16 { +fn __fmah(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi, z: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fma_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y), compiler_rt.f16.fromAbi(z))); +} +pub fn fma_f16(x: f16, y: f16, z: f16) f16 { // TODO: more efficient implementation - return @floatCast(fmaf(x, y, z)); + return @floatCast(fma_f32(x, y, z)); } -pub fn fmaf(x: f32, y: f32, z: f32) callconv(.c) f32 { +fn fmaf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi, z: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fma_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y), compiler_rt.f32.fromAbi(z))); +} +pub fn fma_f32(x: f32, y: f32, z: f32) f32 { const xy = @as(f64, x) * y; const xy_z = xy + z; const u = @as(u64, @bitCast(xy_z)); @@ -42,8 +45,11 @@ pub fn fmaf(x: f32, y: f32, z: f32) callconv(.c) f32 { } } +fn fma(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi, z: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fma_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y), compiler_rt.f64.fromAbi(z))); +} /// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. -pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64 { +pub fn fma_f64(x: f64, y: f64, z: f64) f64 { if (!math.isFinite(x) or !math.isFinite(y)) { return x * y + z; } @@ -90,11 +96,17 @@ pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64 { } } -pub fn __fmax(a: f80, b: f80, c: f80) callconv(.c) f80 { +fn __fmax(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi, c: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fma_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b), compiler_rt.f80.fromAbi(c))); +} +pub fn fma_f80(a: f80, b: f80, c: f80) f80 { // TODO: more efficient implementation - return @floatCast(fmaq(a, b, c)); + return @floatCast(fma_f128(a, b, c)); } +fn fmaq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi, z: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fma_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y), compiler_rt.f128.fromAbi(z))); +} /// Fused multiply-add: Compute x * y + z with a single rounding error. /// /// We use scaling to avoid overflow/underflow, along with the @@ -102,7 +114,7 @@ pub fn __fmax(a: f80, b: f80, c: f80) callconv(.c) f80 { /// /// Dekker, T. A Floating-Point Technique for Extending the /// Available Precision. Numer. Math. 18, 224-242 (1971). -pub fn fmaq(x: f128, y: f128, z: f128) callconv(.c) f128 { +pub fn fma_f128(x: f128, y: f128, z: f128) f128 { if (!math.isFinite(x) or !math.isFinite(y)) { return x * y + z; } @@ -151,10 +163,10 @@ pub fn fmaq(x: f128, y: f128, z: f128) callconv(.c) f128 { pub fn fmal(x: c_longdouble, y: c_longdouble, z: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fma(x, y, z), - 80 => return __fmax(x, y, z), - 128 => return fmaq(x, y, z), - else => @compileError("unreachable"), + 64 => return fma_f64(x, y, z), + 80 => return fma_f80(x, y, z), + 128 => return fma_f128(x, y, z), + else => comptime unreachable, } } @@ -316,35 +328,35 @@ fn dd_mul128(a: f128, b: f128) dd128 { test "32" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f32, fmaf(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(37.45, 5.0, 9.124), 196.374004, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(89.123, 5.0, 9.124), 454.739005, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(37.45, 5.0, 9.124), 196.374004, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(89.123, 5.0, 9.124), 454.739005, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "64" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f64, fma(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f64, fma(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f64, fma(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f64, fma(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f64, fma(37.45, 5.0, 9.124), 196.374, epsilon)); - try expect(math.approxEqAbs(f64, fma(89.123, 5.0, 9.124), 454.739, epsilon)); - try expect(math.approxEqAbs(f64, fma(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(37.45, 5.0, 9.124), 196.374, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(89.123, 5.0, 9.124), 454.739, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "128" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f128, fmaq(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(37.45, 5.0, 9.124), 196.374, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(89.123, 5.0, 9.124), 454.739, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(37.45, 5.0, 9.124), 196.374, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(89.123, 5.0, 9.124), 454.739, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } diff --git a/lib/compiler_rt/fmax.zig b/lib/compiler_rt/fmax.zig index 317d93f2d3e42fcfb88c4f36fe2203dab6bfeed2..f69912472044f62c50733968b382fec866d069c7 100644 --- a/lib/compiler_rt/fmax.zig +++ b/lib/compiler_rt/fmax.zig @@ -10,39 +10,51 @@ comptime { symbol(&fmaxf, "fmaxf"); symbol(&fmax, "fmax"); symbol(&__fmaxx, "__fmaxx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmaxq, "fmaxf128"); - } - symbol(&fmaxq, "fmaxq"); + symbol(&fmaxq, "fmaxf128"); symbol(&fmaxl, "fmaxl"); } -pub fn __fmaxh(x: f16, y: f16) callconv(.c) f16 { +fn __fmaxh(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmax_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y))); +} +pub fn fmax_f16(x: f16, y: f16) f16 { return generic_fmax(f16, x, y); } -pub fn fmaxf(x: f32, y: f32) callconv(.c) f32 { +fn fmaxf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmax_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y))); +} +pub fn fmax_f32(x: f32, y: f32) f32 { return generic_fmax(f32, x, y); } -pub fn fmax(x: f64, y: f64) callconv(.c) f64 { +fn fmax(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmax_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y))); +} +pub fn fmax_f64(x: f64, y: f64) f64 { return generic_fmax(f64, x, y); } -pub fn __fmaxx(x: f80, y: f80) callconv(.c) f80 { +fn __fmaxx(x: compiler_rt.f80.Abi, y: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmax_f80(compiler_rt.f80.fromAbi(x), compiler_rt.f80.fromAbi(y))); +} +pub fn fmax_f80(x: f80, y: f80) f80 { return generic_fmax(f80, x, y); } -pub fn fmaxq(x: f128, y: f128) callconv(.c) f128 { +fn fmaxq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmax_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y))); +} +pub fn fmax_f128(x: f128, y: f128) f128 { return generic_fmax(f128, x, y); } pub fn fmaxl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmax(x, y), - 80 => return __fmaxx(x, y), - 128 => return fmaxq(x, y), - else => @compileError("unreachable"), + 64 => return fmax_f64(x, y), + 80 => return fmax_f80(x, y), + 128 => return fmax_f128(x, y), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fmin.zig b/lib/compiler_rt/fmin.zig index 36cf9c121bbf17c1e282cfcf982f69ce7f1ec17c..bece9262f2a673919e33260576c2ce7d8730cdee 100644 --- a/lib/compiler_rt/fmin.zig +++ b/lib/compiler_rt/fmin.zig @@ -10,39 +10,51 @@ comptime { symbol(&fminf, "fminf"); symbol(&fmin, "fmin"); symbol(&__fminx, "__fminx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fminq, "fminf128"); - } - symbol(&fminq, "fminq"); + symbol(&fminq, "fminf128"); symbol(&fminl, "fminl"); } -pub fn __fminh(x: f16, y: f16) callconv(.c) f16 { +fn __fminh(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmin_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y))); +} +pub fn fmin_f16(x: f16, y: f16) f16 { return generic_fmin(f16, x, y); } -pub fn fminf(x: f32, y: f32) callconv(.c) f32 { +fn fminf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmin_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y))); +} +pub fn fmin_f32(x: f32, y: f32) f32 { return generic_fmin(f32, x, y); } -pub fn fmin(x: f64, y: f64) callconv(.c) f64 { +fn fmin(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmin_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y))); +} +pub fn fmin_f64(x: f64, y: f64) f64 { return generic_fmin(f64, x, y); } -pub fn __fminx(x: f80, y: f80) callconv(.c) f80 { +fn __fminx(x: compiler_rt.f80.Abi, y: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmin_f80(compiler_rt.f80.fromAbi(x), compiler_rt.f80.fromAbi(y))); +} +pub fn fmin_f80(x: f80, y: f80) f80 { return generic_fmin(f80, x, y); } -pub fn fminq(x: f128, y: f128) callconv(.c) f128 { +fn fminq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmin_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y))); +} +pub fn fmin_f128(x: f128, y: f128) f128 { return generic_fmin(f128, x, y); } pub fn fminl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmin(x, y), - 80 => return __fminx(x, y), - 128 => return fminq(x, y), - else => @compileError("unreachable"), + 64 => return fmin_f64(x, y), + 80 => return fmin_f80(x, y), + 128 => return fmin_f128(x, y), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fmod.zig b/lib/compiler_rt/fmod.zig index 009eedd8ac84ab7eb905a74900fc17d07e8be421..951b90d06e529e8a3a2606d7fe0eff1dcd9d667a 100644 --- a/lib/compiler_rt/fmod.zig +++ b/lib/compiler_rt/fmod.zig @@ -12,29 +12,38 @@ comptime { symbol(&fmodf, "fmodf"); symbol(&fmod, "fmod"); symbol(&__fmodx, "__fmodx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmodq, "fmodf128"); - } - symbol(&fmodq, "fmodq"); + symbol(&fmodq, "fmodf128"); symbol(&fmodl, "fmodl"); } -pub fn __fmodh(x: f16, y: f16) callconv(.c) f16 { +fn __fmodh(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmod_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn fmod_f16(x: f16, y: f16) f16 { // TODO: more efficient implementation - return @floatCast(fmodf(x, y)); + return @floatCast(fmod_f32(x, y)); } -pub fn fmodf(x: f32, y: f32) callconv(.c) f32 { +fn fmodf(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmod_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +pub fn fmod_f32(x: f32, y: f32) f32 { return generic_fmod(f32, x, y); } -pub fn fmod(x: f64, y: f64) callconv(.c) f64 { +fn fmod(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmod_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +pub fn fmod_f64(x: f64, y: f64) f64 { return generic_fmod(f64, x, y); } +fn __fmodx(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmod_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} /// fmodx - floating modulo large, returns the remainder of division for f80 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits -pub fn __fmodx(a: f80, b: f80) callconv(.c) f80 { +pub fn fmod_f80(a: f80, b: f80) f80 { const T = f80; const Z = @Int(.unsigned, @bitSizeOf(T)); @@ -130,9 +139,12 @@ pub fn __fmodx(a: f80, b: f80) callconv(.c) f80 { } } +fn fmodq(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmod_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} /// fmodq - floating modulo large, returns the remainder of division for f128 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits -pub fn fmodq(a: f128, b: f128) callconv(.c) f128 { +pub fn fmod_f128(a: f128, b: f128) f128 { var amod = a; var bmod = b; const aPtr_u64: [*]u64 = @ptrCast(&amod); @@ -251,10 +263,10 @@ pub fn fmodq(a: f128, b: f128) callconv(.c) f128 { pub fn fmodl(a: c_longdouble, b: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmod(a, b), - 80 => return __fmodx(a, b), - 128 => return fmodq(a, b), - else => @compileError("unreachable"), + 64 => return fmod_f64(a, b), + 80 => return fmod_f80(a, b), + 128 => return fmod_f128(a, b), + else => comptime unreachable, } } @@ -342,42 +354,42 @@ inline fn generic_fmod(comptime T: type, x: T, y: T) T { return @bitCast(ux); } -test "fmodf" { +test fmod_f32 { const nan_val = math.nan(f32); const inf_val = math.inf(f32); - try std.testing.expect(math.isNan(fmodf(nan_val, 1.0))); - try std.testing.expect(math.isNan(fmodf(1.0, nan_val))); - try std.testing.expect(math.isNan(fmodf(inf_val, 1.0))); - try std.testing.expect(math.isNan(fmodf(0.0, 0.0))); - try std.testing.expect(math.isNan(fmodf(1.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f32(nan_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f32(1.0, nan_val))); + try std.testing.expect(math.isNan(fmod_f32(inf_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f32(0.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f32(1.0, 0.0))); - try std.testing.expectEqual(@as(f32, 0.0), fmodf(0.0, 2.0)); - try std.testing.expectEqual(@as(f32, -0.0), fmodf(-0.0, 2.0)); + try std.testing.expectEqual(@as(f32, 0.0), fmod_f32(0.0, 2.0)); + try std.testing.expectEqual(@as(f32, -0.0), fmod_f32(-0.0, 2.0)); - try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, 10.0)); - try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, -10.0)); - try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, 10.0)); - try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, -10.0)); + try std.testing.expectEqual(@as(f32, -2.0), fmod_f32(-32.0, 10.0)); + try std.testing.expectEqual(@as(f32, -2.0), fmod_f32(-32.0, -10.0)); + try std.testing.expectEqual(@as(f32, 2.0), fmod_f32(32.0, 10.0)); + try std.testing.expectEqual(@as(f32, 2.0), fmod_f32(32.0, -10.0)); } -test "fmod" { +test fmod_f64 { const nan_val = math.nan(f64); const inf_val = math.inf(f64); - try std.testing.expect(math.isNan(fmod(nan_val, 1.0))); - try std.testing.expect(math.isNan(fmod(1.0, nan_val))); - try std.testing.expect(math.isNan(fmod(inf_val, 1.0))); - try std.testing.expect(math.isNan(fmod(0.0, 0.0))); - try std.testing.expect(math.isNan(fmod(1.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f64(nan_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f64(1.0, nan_val))); + try std.testing.expect(math.isNan(fmod_f64(inf_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f64(0.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f64(1.0, 0.0))); - try std.testing.expectEqual(@as(f64, 0.0), fmod(0.0, 2.0)); - try std.testing.expectEqual(@as(f64, -0.0), fmod(-0.0, 2.0)); + try std.testing.expectEqual(@as(f64, 0.0), fmod_f64(0.0, 2.0)); + try std.testing.expectEqual(@as(f64, -0.0), fmod_f64(-0.0, 2.0)); - try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, 10.0)); - try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, -10.0)); - try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, 10.0)); - try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, -10.0)); + try std.testing.expectEqual(@as(f64, -2.0), fmod_f64(-32.0, 10.0)); + try std.testing.expectEqual(@as(f64, -2.0), fmod_f64(-32.0, -10.0)); + try std.testing.expectEqual(@as(f64, 2.0), fmod_f64(32.0, 10.0)); + try std.testing.expectEqual(@as(f64, 2.0), fmod_f64(32.0, -10.0)); } test { diff --git a/lib/compiler_rt/fmodq_test.zig b/lib/compiler_rt/fmodq_test.zig index 07ddb8d182e41fe2ff80414aeff256728e1ce365..b98dc0762e664f09b0d648e290658bf4502da416 100644 --- a/lib/compiler_rt/fmodq_test.zig +++ b/lib/compiler_rt/fmodq_test.zig @@ -1,52 +1,52 @@ const std = @import("std"); -const fmod = @import("fmod.zig"); +const fmod_f128 = @import("fmod.zig").fmod_f128; const testing = std.testing; -fn test_fmodq(a: f128, b: f128, exp: f128) !void { - const res = fmod.fmodq(a, b); +fn test_fmod_f128(a: f128, b: f128, exp: f128) !void { + const res = fmod_f128(a, b); try testing.expect(exp == res); } -fn test_fmodq_nans() !void { - try testing.expect(std.math.isNan(fmod.fmodq(1.0, std.math.nan(f128)))); - try testing.expect(std.math.isNan(fmod.fmodq(1.0, -std.math.nan(f128)))); - try testing.expect(std.math.isNan(fmod.fmodq(std.math.nan(f128), 1.0))); - try testing.expect(std.math.isNan(fmod.fmodq(-std.math.nan(f128), 1.0))); +fn test_fmod_f128_nans() !void { + try testing.expect(std.math.isNan(fmod_f128(1.0, std.math.nan(f128)))); + try testing.expect(std.math.isNan(fmod_f128(1.0, -std.math.nan(f128)))); + try testing.expect(std.math.isNan(fmod_f128(std.math.nan(f128), 1.0))); + try testing.expect(std.math.isNan(fmod_f128(-std.math.nan(f128), 1.0))); } -fn test_fmodq_infs() !void { - try testing.expect(fmod.fmodq(1.0, std.math.inf(f128)) == 1.0); - try testing.expect(fmod.fmodq(1.0, -std.math.inf(f128)) == 1.0); - try testing.expect(std.math.isNan(fmod.fmodq(std.math.inf(f128), 1.0))); - try testing.expect(std.math.isNan(fmod.fmodq(-std.math.inf(f128), 1.0))); +fn test_fmod_f128_infs() !void { + try testing.expect(fmod_f128(1.0, std.math.inf(f128)) == 1.0); + try testing.expect(fmod_f128(1.0, -std.math.inf(f128)) == 1.0); + try testing.expect(std.math.isNan(fmod_f128(std.math.inf(f128), 1.0))); + try testing.expect(std.math.isNan(fmod_f128(-std.math.inf(f128), 1.0))); } -test "fmodq" { - try test_fmodq(6.8, 4.0, 2.8); - try test_fmodq(6.8, -4.0, 2.8); - try test_fmodq(-6.8, 4.0, -2.8); - try test_fmodq(-6.8, -4.0, -2.8); - try test_fmodq(3.0, 2.0, 1.0); - try test_fmodq(-5.0, 3.0, -2.0); - try test_fmodq(3.0, 2.0, 1.0); - try test_fmodq(1.0, 2.0, 1.0); - try test_fmodq(0.0, 1.0, 0.0); - try test_fmodq(-0.0, 1.0, -0.0); - try test_fmodq(7046119.0, 5558362.0, 1487757.0); - try test_fmodq(9010357.0, 1957236.0, 1181413.0); - try test_fmodq(5192296858534827628530496329220095, 10.0, 5.0); - try test_fmodq(5192296858534827628530496329220095, 922337203681230954775807, 220474884073715748246157); +test fmod_f128 { + try test_fmod_f128(6.8, 4.0, 2.8); + try test_fmod_f128(6.8, -4.0, 2.8); + try test_fmod_f128(-6.8, 4.0, -2.8); + try test_fmod_f128(-6.8, -4.0, -2.8); + try test_fmod_f128(3.0, 2.0, 1.0); + try test_fmod_f128(-5.0, 3.0, -2.0); + try test_fmod_f128(3.0, 2.0, 1.0); + try test_fmod_f128(1.0, 2.0, 1.0); + try test_fmod_f128(0.0, 1.0, 0.0); + try test_fmod_f128(-0.0, 1.0, -0.0); + try test_fmod_f128(7046119.0, 5558362.0, 1487757.0); + try test_fmod_f128(9010357.0, 1957236.0, 1181413.0); + try test_fmod_f128(5192296858534827628530496329220095, 10.0, 5.0); + try test_fmod_f128(5192296858534827628530496329220095, 922337203681230954775807, 220474884073715748246157); // Denormals const a1: f128 = 0xedcb34a235253948765432134674p-16494; const b1: f128 = 0x5d2e38791cfbc0737402da5a9518p-16494; const exp1: f128 = 0x336ec3affb2db8618e4e7d5e1c44p-16494; - try test_fmodq(a1, b1, exp1); + try test_fmod_f128(a1, b1, exp1); const a2: f128 = 0x0.7654_3210_fdec_ba98_7654_3210_fdecp-16382; const b2: f128 = 0x0.0012_fdac_bdef_1234_fdec_3222_1111p-16382; const exp2: f128 = 0x0.0001_aecd_9d66_4a6e_67b7_d7d0_a901p-16382; - try test_fmodq(a2, b2, exp2); + try test_fmod_f128(a2, b2, exp2); - try test_fmodq_nans(); - try test_fmodq_infs(); + try test_fmod_f128_nans(); + try test_fmod_f128_infs(); } diff --git a/lib/compiler_rt/fmodx_test.zig b/lib/compiler_rt/fmodx_test.zig index ca8229147ab693264b555676af664e7bf8acccbc..b32d354094ed97a1ab8d7c9d840610b9a8ac12a7 100644 --- a/lib/compiler_rt/fmodx_test.zig +++ b/lib/compiler_rt/fmodx_test.zig @@ -1,52 +1,52 @@ const std = @import("std"); const builtin = @import("builtin"); -const fmod = @import("fmod.zig"); +const fmod_f80 = @import("fmod.zig").fmod_f80; const testing = std.testing; -fn test_fmodx(a: f80, b: f80, exp: f80) !void { - const res = fmod.__fmodx(a, b); +fn test_fmod_f80(a: f80, b: f80, exp: f80) !void { + const res = fmod_f80(a, b); try testing.expect(exp == res); } -fn test_fmodx_nans() !void { - try testing.expect(std.math.isNan(fmod.__fmodx(1.0, std.math.nan(f80)))); - try testing.expect(std.math.isNan(fmod.__fmodx(1.0, -std.math.nan(f80)))); - try testing.expect(std.math.isNan(fmod.__fmodx(std.math.nan(f80), 1.0))); - try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.nan(f80), 1.0))); +fn test_fmod_f80_nans() !void { + try testing.expect(std.math.isNan(fmod_f80(1.0, std.math.nan(f80)))); + try testing.expect(std.math.isNan(fmod_f80(1.0, -std.math.nan(f80)))); + try testing.expect(std.math.isNan(fmod_f80(std.math.nan(f80), 1.0))); + try testing.expect(std.math.isNan(fmod_f80(-std.math.nan(f80), 1.0))); } -fn test_fmodx_infs() !void { - try testing.expect(fmod.__fmodx(1.0, std.math.inf(f80)) == 1.0); - try testing.expect(fmod.__fmodx(1.0, -std.math.inf(f80)) == 1.0); - try testing.expect(std.math.isNan(fmod.__fmodx(std.math.inf(f80), 1.0))); - try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.inf(f80), 1.0))); +fn test_fmod_f80_infs() !void { + try testing.expect(fmod_f80(1.0, std.math.inf(f80)) == 1.0); + try testing.expect(fmod_f80(1.0, -std.math.inf(f80)) == 1.0); + try testing.expect(std.math.isNan(fmod_f80(std.math.inf(f80), 1.0))); + try testing.expect(std.math.isNan(fmod_f80(-std.math.inf(f80), 1.0))); } -test "fmodx" { - try test_fmodx(6.4, 4.0, 2.4); - try test_fmodx(6.4, -4.0, 2.4); - try test_fmodx(-6.4, 4.0, -2.4); - try test_fmodx(-6.4, -4.0, -2.4); - try test_fmodx(3.0, 2.0, 1.0); - try test_fmodx(-5.0, 3.0, -2.0); - try test_fmodx(3.0, 2.0, 1.0); - try test_fmodx(1.0, 2.0, 1.0); - try test_fmodx(0.0, 1.0, 0.0); - try test_fmodx(-0.0, 1.0, -0.0); - try test_fmodx(7046119.0, 5558362.0, 1487757.0); - try test_fmodx(9010357.0, 1957236.0, 1181413.0); - try test_fmodx(9223372036854775807, 10.0, 7.0); +test fmod_f80 { + try test_fmod_f80(6.4, 4.0, 2.4); + try test_fmod_f80(6.4, -4.0, 2.4); + try test_fmod_f80(-6.4, 4.0, -2.4); + try test_fmod_f80(-6.4, -4.0, -2.4); + try test_fmod_f80(3.0, 2.0, 1.0); + try test_fmod_f80(-5.0, 3.0, -2.0); + try test_fmod_f80(3.0, 2.0, 1.0); + try test_fmod_f80(1.0, 2.0, 1.0); + try test_fmod_f80(0.0, 1.0, 0.0); + try test_fmod_f80(-0.0, 1.0, -0.0); + try test_fmod_f80(7046119.0, 5558362.0, 1487757.0); + try test_fmod_f80(9010357.0, 1957236.0, 1181413.0); + try test_fmod_f80(9223372036854775807, 10.0, 7.0); // Denormals const a1: f80 = 0x0.76e5_9a51_1a92_9ca4p-16381; const b1: f80 = 0x0.2e97_1c3c_8e7d_e03ap-16381; const exp1: f80 = 0x0.19b7_61d7_fd96_dc30p-16381; - try test_fmodx(a1, b1, exp1); + try test_fmod_f80(a1, b1, exp1); const a2: f80 = 0x0.76e5_9a51_1a92_9ca4p-16381; const b2: f80 = 0x0.0e97_1c3c_8e7d_e03ap-16381; const exp2: f80 = 0x0.022c_b86c_a6a3_9ad4p-16381; - try test_fmodx(a2, b2, exp2); + try test_fmod_f80(a2, b2, exp2); - try test_fmodx_nans(); - try test_fmodx_infs(); + try test_fmod_f80_nans(); + try test_fmod_f80_infs(); } diff --git a/lib/compiler_rt/gedf2.zig b/lib/compiler_rt/gedf2.zig deleted file mode 100644 index f6b4b6d718fd20d8068244cfa6250f030f890e92..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gedf2.zig +++ /dev/null @@ -1,35 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpge, "__aeabi_dcmpge"); - symbol(&__aeabi_dcmpgt, "__aeabi_dcmpgt"); - } else { - symbol(&__gedf2, "__gedf2"); - symbol(&__gtdf2, "__gtdf2"); - } -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gedf2(a: f64, b: f64) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f64, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gtdf2(a: f64, b: f64) callconv(.c) i32 { - return __gedf2(a, b); -} - -fn __aeabi_dcmpge(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.GE, a, b) != .Less); -} - -fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.GE, a, b) == .Greater); -} diff --git a/lib/compiler_rt/gehf2.zig b/lib/compiler_rt/gehf2.zig deleted file mode 100644 index 8008a06849887d2f317be4517a5cb6c485c2675a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gehf2.zig +++ /dev/null @@ -1,21 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const symbol = @import("../compiler_rt.zig").symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__gehf2, "__gehf2"); - symbol(&__gthf2, "__gthf2"); -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gehf2(a: f16, b: f16) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f16, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gthf2(a: f16, b: f16) callconv(.c) i32 { - return __gehf2(a, b); -} diff --git a/lib/compiler_rt/gesf2.zig b/lib/compiler_rt/gesf2.zig deleted file mode 100644 index 7f5022104eba9378efe6184befcd7f40f479306f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gesf2.zig +++ /dev/null @@ -1,35 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fcmpge, "__aeabi_fcmpge"); - symbol(&__aeabi_fcmpgt, "__aeabi_fcmpgt"); - } else { - symbol(&__gesf2, "__gesf2"); - symbol(&__gtsf2, "__gtsf2"); - } -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gesf2(a: f32, b: f32) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f32, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gtsf2(a: f32, b: f32) callconv(.c) i32 { - return __gesf2(a, b); -} - -fn __aeabi_fcmpge(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f32, comparef.GE, a, b) != .Less); -} - -fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f32, comparef.LE, a, b) == .Greater); -} diff --git a/lib/compiler_rt/getf2.zig b/lib/compiler_rt/getf2.zig deleted file mode 100644 index 88a91600f1e32c5f7124f5e9be9d5828b2471f2e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/getf2.zig +++ /dev/null @@ -1,26 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__getf2, "__gekf2"); - symbol(&__gttf2, "__gtkf2"); - } - symbol(&__getf2, "__getf2"); - symbol(&__gttf2, "__gttf2"); -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -fn __getf2(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -fn __gttf2(a: f128, b: f128) callconv(.c) i32 { - return __getf2(a, b); -} diff --git a/lib/compiler_rt/gexf2.zig b/lib/compiler_rt/gexf2.zig deleted file mode 100644 index 9f1f356187cdf9c7b85be2d49f9e2e73439f381b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gexf2.zig +++ /dev/null @@ -1,15 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__gexf2, "__gexf2"); - symbol(&__gtxf2, "__gtxf2"); -} - -fn __gexf2(a: f80, b: f80) callconv(.c) i32 { - return @backingInt(comparef.cmp_f80(comparef.GE, a, b)); -} - -fn __gtxf2(a: f80, b: f80) callconv(.c) i32 { - return __gexf2(a, b); -} diff --git a/lib/compiler_rt/int.zig b/lib/compiler_rt/int.zig index 48c900207bce8946adf6bb9cafe9407b214946d4..e387be858213a7afb575bd3b81f62e016e16a19e 100644 --- a/lib/compiler_rt/int.zig +++ b/lib/compiler_rt/int.zig @@ -36,7 +36,7 @@ comptime { pub fn __divmodti4(a: i128, b: i128, rem: *i128) callconv(.c) i128 { const d = __divti3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } @@ -69,7 +69,7 @@ fn test_one_divmodti4(a: i128, b: i128, expected_q: i128, expected_r: i128) !voi pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.c) i64 { const d = __divdi3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } @@ -79,21 +79,20 @@ fn test_one_divmoddi4(a: i64, b: i64, expected_q: i64, expected_r: i64) !void { try testing.expect(q == expected_q and r == expected_r); } -const cases__divmoddi4 = - [_][4]i64{ - [_]i64{ 0, 1, 0, 0 }, - [_]i64{ 0, -1, 0, 0 }, - [_]i64{ 2, 1, 2, 0 }, - [_]i64{ 2, -1, -2, 0 }, - [_]i64{ -2, 1, -2, 0 }, - [_]i64{ -2, -1, 2, 0 }, - [_]i64{ 7, 5, 1, 2 }, - [_]i64{ -7, 5, -1, -2 }, - [_]i64{ 19, 5, 3, 4 }, - [_]i64{ 19, -5, -3, 4 }, - [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000000))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000000))), 0 }, - [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000007))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000001))), -1 }, - }; +const cases__divmoddi4 = [_][4]i64{ + [_]i64{ 0, 1, 0, 0 }, + [_]i64{ 0, -1, 0, 0 }, + [_]i64{ 2, 1, 2, 0 }, + [_]i64{ 2, -1, -2, 0 }, + [_]i64{ -2, 1, -2, 0 }, + [_]i64{ -2, -1, 2, 0 }, + [_]i64{ 7, 5, 1, 2 }, + [_]i64{ -7, 5, -1, -2 }, + [_]i64{ 19, 5, 3, 4 }, + [_]i64{ 19, -5, -3, 4 }, + [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000000))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000000))), 0 }, + [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000007))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000001))), -1 }, +}; test "test_divmoddi4" { for (cases__divmoddi4) |case| { @@ -105,10 +104,6 @@ pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.c) u64 { return udivmod(u64, a, b, maybe_rem); } -test "test_udivmoddi4" { - _ = @import("udivmoddi4_test.zig"); -} - pub fn __divdi3(a: i64, b: i64) callconv(.c) i64 { // Set aside the sign of the quotient. const sign: u64 = @bitCast((a ^ b) >> 63); @@ -209,25 +204,24 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) !void { pub fn __divmodsi4(a: i32, b: i32, rem: *i32) callconv(.c) i32 { const d = __divsi3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } -const cases__divmodsi4 = - [_][4]i32{ - [_]i32{ 0, 1, 0, 0 }, - [_]i32{ 0, -1, 0, 0 }, - [_]i32{ 2, 1, 2, 0 }, - [_]i32{ 2, -1, -2, 0 }, - [_]i32{ -2, 1, -2, 0 }, - [_]i32{ -2, -1, 2, 0 }, - [_]i32{ 7, 5, 1, 2 }, - [_]i32{ -7, 5, -1, -2 }, - [_]i32{ 19, 5, 3, 4 }, - [_]i32{ 19, -5, -3, 4 }, - [_]i32{ @bitCast(@as(u32, 0x80000000)), 8, @bitCast(@as(u32, 0xf0000000)), 0 }, - [_]i32{ @bitCast(@as(u32, 0x80000007)), 8, @bitCast(@as(u32, 0xf0000001)), -1 }, - }; +const cases__divmodsi4 = [_][4]i32{ + [_]i32{ 0, 1, 0, 0 }, + [_]i32{ 0, -1, 0, 0 }, + [_]i32{ 2, 1, 2, 0 }, + [_]i32{ 2, -1, -2, 0 }, + [_]i32{ -2, 1, -2, 0 }, + [_]i32{ -2, -1, 2, 0 }, + [_]i32{ 7, 5, 1, 2 }, + [_]i32{ -7, 5, -1, -2 }, + [_]i32{ 19, 5, 3, 4 }, + [_]i32{ 19, -5, -3, 4 }, + [_]i32{ @bitCast(@as(u32, 0x80000000)), 8, @bitCast(@as(u32, 0xf0000000)), 0 }, + [_]i32{ @bitCast(@as(u32, 0x80000007)), 8, @bitCast(@as(u32, 0xf0000001)), -1 }, +}; fn test_one_divmodsi4(a: i32, b: i32, expected_q: i32, expected_r: i32) !void { var r: i32 = undefined; @@ -243,7 +237,7 @@ test "test_divmodsi4" { pub fn __udivmodsi4(a: u32, b: u32, rem: *u32) callconv(.c) u32 { const d = __udivsi3(a, b); - rem.* = @bitCast(@as(i32, @bitCast(a)) -% (@as(i32, @bitCast(d)) * @as(i32, @bitCast(b)))); + rem.* = a - d * b; return d; } @@ -486,7 +480,7 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) !void { } pub fn __modsi3(n: i32, d: i32) callconv(.c) i32 { - return n -% __divsi3(n, d) * d; + return n - __divsi3(n, d) *% d; } test "test_modsi3" { @@ -515,7 +509,7 @@ fn test_one_modsi3(a: i32, b: i32, expected_r: i32) !void { } pub fn __umodsi3(n: u32, d: u32) callconv(.c) u32 { - return n -% __udivsi3(n, d) * d; + return n - __udivsi3(n, d) * d; } test "test_umodsi3" { @@ -663,3 +657,8 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void { const r: u32 = __umodsi3(a, b); try testing.expect(r == expected_r); } + +test { + _ = @import("udivmodsi4_test.zig"); + _ = @import("udivmoddi4_test.zig"); +} diff --git a/lib/compiler_rt/int_from_float.zig b/lib/compiler_rt/int_from_float.zig index 5445e7fb7c6d36111d89112350b5bfc9ced375c8..8eb4c2fcbc79f9d254255372062e473443bffdde 100644 --- a/lib/compiler_rt/int_from_float.zig +++ b/lib/compiler_rt/int_from_float.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const math = std.math; const Log2Int = std.math.Log2Int; @@ -6,29 +7,532 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; comptime { - symbol(&__fixxfti, "__fixxfti"); symbol(&__fixhfsi, "__fixhfsi"); symbol(&__fixhfdi, "__fixhfdi"); symbol(&__fixhfti, "__fixhfti"); + symbol(&__fixhfei, "__fixhfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2iz, "__aeabi_f2iz"); + symbol(&__aeabi_f2lz, "__aeabi_f2lz"); + symbol(&__aeabi_fixsfti, "__fixsfti"); + } else { + symbol(&__fixsfsi, "__fixsfsi"); + symbol(&__fixsfdi, "__fixsfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixsfdi, "__stoi64"); + symbol(&__fixsfti, "__fixsfti"); + } + symbol(&__fixsfei, "__fixsfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2iz, "__aeabi_d2iz"); + symbol(&__aeabi_d2lz, "__aeabi_d2lz"); + symbol(&__aeabi_fixdfti, "__fixdfti"); + } else { + symbol(&__fixdfsi, "__fixdfsi"); + symbol(&__fixdfdi, "__fixdfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixdfdi, "__dtoi64"); + symbol(&__fixdfti, "__fixdfti"); + } + symbol(&__fixdfei, "__fixdfei"); + + symbol(&__fixxfsi, "__fixxfsi"); + symbol(&__fixxfdi, "__fixxfdi"); + symbol(&__fixxfti, "__fixxfti"); + symbol(&__fixxfei, "__fixxfei"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__fixtfsi, "__fixkfsi"); + symbol(&__fixtfdi, "__fixkfdi"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtoi, "_Qp_qtoi"); + symbol(&_Qp_qtox, "_Qp_qtox"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__fixtfsi, "_Q_qtoi"); + symbol(&__fixtfdi, "_Q_qtoll"); + } else { + symbol(&__fixtfsi, "__fixtfsi"); + symbol(&__fixtfdi, "__fixtfdi"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__fixtfti, "__fixkfti"); + symbol(&__fixtfei, "__fixkfei"); + } else { + symbol(&__fixtfti, "__fixtfti"); + symbol(&__fixtfei, "__fixtfei"); + } +} + +fn __fixhfsi(a: compiler_rt.f16.Abi) callconv(.c) i32 { + return i32_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i32_intFromFloat_f16(a: f16) i32 { + return intFromFloat(i32, a); } -pub fn __fixhfti(a: f16) callconv(.c) i128 { +fn __fixhfdi(a: compiler_rt.f16.Abi) callconv(.c) i64 { + return i64_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i64_intFromFloat_f16(a: f16) i64 { + return intFromFloat(i64, a); +} + +fn __fixhfti(a: compiler_rt.f16.Abi) callconv(.c) i128 { + return i128_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i128_intFromFloat_f16(a: f16) i128 { return intFromFloat(i128, a); } -fn __fixhfdi(a: f16) callconv(.c) i64 { +fn __fixhfei(r: [*]u8, bits: usize, a: compiler_rt.f16.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f16(r[0..byte_size], compiler_rt.f16.fromAbi(a)); +} +pub fn signed_intFromFloat_f16(result: []u8, a: f16) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixsfsi(a: compiler_rt.f32.Abi) callconv(.c) i32 { + return i32_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2iz(a: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return i32_intFromFloat_f32(a); +} +pub fn i32_intFromFloat_f32(a: f32) i32 { + return intFromFloat(i32, a); +} + +fn __fixsfdi(a: compiler_rt.f32.Abi) callconv(.c) i64 { + return i64_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2lz(a: f32) callconv(.{ .arm_aapcs = .{} }) i64 { + return i64_intFromFloat_f32(a); +} +pub fn i64_intFromFloat_f32(a: f32) i64 { return intFromFloat(i64, a); } -fn __fixhfsi(a: f16) callconv(.c) i32 { +fn __fixsfti(a: compiler_rt.f32.Abi) callconv(.c) i128 { + return i128_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_fixsfti(_: compiler_rt.f32.Abi) callconv(.naked) i128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r1, r0 + \\ mov r0, sp + \\ bl %[__fixsfti] + \\ pop {r0-r4, pc} + : + : [__fixsfti] "X" (&__fixsfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixsfti] + \\ pop {r0-r4, pc} + : + : [__fixsfti] "X" (&__fixsfti), + ), + } +} +pub fn i128_intFromFloat_f32(a: f32) i128 { + return intFromFloat(i128, a); +} + +fn __fixsfei(r: [*]u8, bits: usize, a: compiler_rt.f32.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f32(r[0..byte_size], compiler_rt.f32.fromAbi(a)); +} +pub fn signed_intFromFloat_f32(result: []u8, a: f32) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixdfsi(a: compiler_rt.f64.Abi) callconv(.c) i32 { + return i32_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2iz(a: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return i32_intFromFloat_f64(a); +} +pub fn i32_intFromFloat_f64(a: f64) i32 { return intFromFloat(i32, a); } -pub fn __fixxfti(a: f80) callconv(.c) i128 { +fn __fixdfdi(a: compiler_rt.f64.Abi) callconv(.c) i64 { + return i64_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2lz(a: f64) callconv(.{ .arm_aapcs = .{} }) i64 { + return i64_intFromFloat_f64(a); +} +pub fn i64_intFromFloat_f64(a: f64) i64 { + return intFromFloat(i64, a); +} + +fn __fixdfti(a: compiler_rt.f64.Abi) callconv(.c) i128 { + return i128_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_fixdfti(_: compiler_rt.f64.Abi) callconv(.naked) i128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r3, r1 + \\ mov r2, r0 + \\ mov r0, sp + \\ bl %[__fixdfti] + \\ pop {r0-r4, pc} + : + : [__fixdfti] "X" (&__fixdfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixdfti] + \\ pop {r0-r4, pc} + : + : [__fixdfti] "X" (&__fixdfti), + ), + } +} +pub fn i128_intFromFloat_f64(a: f64) i128 { return intFromFloat(i128, a); } -pub inline fn intFromFloat(comptime I: type, a: anytype) I { +fn __fixdfei(r: [*]u8, bits: usize, a: compiler_rt.f64.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f64(r[0..byte_size], compiler_rt.f64.fromAbi(a)); +} +pub fn signed_intFromFloat_f64(result: []u8, a: f64) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixxfsi(a: compiler_rt.f80.Abi) callconv(.c) i32 { + return i32_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i32_intFromFloat_f80(a: f80) i32 { + return intFromFloat(i32, a); +} + +fn __fixxfdi(a: compiler_rt.f80.Abi) callconv(.c) i64 { + return i64_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i64_intFromFloat_f80(a: f80) i64 { + return intFromFloat(i64, a); +} + +fn __fixxfti(a: compiler_rt.f80.Abi) callconv(.c) i128 { + return i128_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i128_intFromFloat_f80(a: f80) i128 { + return intFromFloat(i128, a); +} + +fn __fixxfei(r: [*]u8, bits: usize, a: compiler_rt.f80.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f80(r[0..byte_size], compiler_rt.f80.fromAbi(a)); +} +pub fn signed_intFromFloat_f80(result: []u8, a: f80) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixtfsi(a: compiler_rt.f128.Abi) callconv(.c) i32 { + return i32_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoi(a: *const f128) callconv(.c) i32 { + return i32_intFromFloat_f128(a.*); +} +pub fn i32_intFromFloat_f128(a: f128) i32 { + return intFromFloat(i32, a); +} + +fn __fixtfdi(a: compiler_rt.f128.Abi) callconv(.c) i64 { + return i64_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtox(a: *const f128) callconv(.c) i64 { + return i64_intFromFloat_f128(a.*); +} +pub fn i64_intFromFloat_f128(a: f128) i64 { + return intFromFloat(i64, a); +} + +fn __fixtfti(a: compiler_rt.f128.Abi) callconv(.c) i128 { + return i128_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +pub fn i128_intFromFloat_f128(a: f128) i128 { + return intFromFloat(i128, a); +} + +fn __fixtfei(r: [*]u8, bits: usize, a: compiler_rt.f128.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f128(r[0..byte_size], compiler_rt.f128.fromAbi(a)); +} +pub fn signed_intFromFloat_f128(result: []u8, a: f128) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +comptime { + symbol(&__fixunshfsi, "__fixunshfsi"); + symbol(&__fixunshfdi, "__fixunshfdi"); + symbol(&__fixunshfti, "__fixunshfti"); + symbol(&__fixunshfei, "__fixunshfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2uiz, "__aeabi_f2uiz"); + symbol(&__aeabi_f2ulz, "__aeabi_f2ulz"); + symbol(&__aeabi_fixunssfti, "__fixunssfti"); + } else { + symbol(&__fixunssfsi, "__fixunssfsi"); + symbol(&__fixunssfdi, "__fixunssfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixunssfdi, "__stou64"); + symbol(&__fixunssfti, "__fixunssfti"); + } + symbol(&__fixunssfei, "__fixunssfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2uiz, "__aeabi_d2uiz"); + symbol(&__aeabi_d2ulz, "__aeabi_d2ulz"); + symbol(&__aeabi_fixunsdfti, "__fixunsdfti"); + } else { + symbol(&__fixunsdfsi, "__fixunsdfsi"); + symbol(&__fixunsdfdi, "__fixunsdfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixunsdfdi, "__dtou64"); + symbol(&__fixunsdfti, "__fixunsdfti"); + } + symbol(&__fixunsdfei, "__fixunsdfei"); + + symbol(&__fixunsxfsi, "__fixunsxfsi"); + symbol(&__fixunsxfdi, "__fixunsxfdi"); + symbol(&__fixunsxfti, "__fixunsxfti"); + symbol(&__fixunsxfei, "__fixunsxfei"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__fixunstfsi, "__fixunskfsi"); + symbol(&__fixunstfdi, "__fixunskfdi"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtoui, "_Qp_qtoui"); + symbol(&_Qp_qtoux, "_Qp_qtoux"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__fixunstfsi, "_Q_qtou"); + symbol(&__fixunstfdi, "_Q_qtoull"); + } else { + symbol(&__fixunstfsi, "__fixunstfsi"); + symbol(&__fixunstfdi, "__fixunstfdi"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__fixunstfti, "__fixunskfti"); + symbol(&__fixunstfei, "__fixunskfei"); + } else { + symbol(&__fixunstfti, "__fixunstfti"); + symbol(&__fixunstfei, "__fixunstfei"); + } +} + +fn __fixunshfsi(a: compiler_rt.f16.Abi) callconv(.c) u32 { + return u32_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u32_intFromFloat_f16(a: f16) u32 { + return intFromFloat(u32, a); +} + +fn __fixunshfdi(a: compiler_rt.f16.Abi) callconv(.c) u64 { + return u64_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u64_intFromFloat_f16(a: f16) u64 { + return intFromFloat(u64, a); +} + +fn __fixunshfti(a: compiler_rt.f16.Abi) callconv(.c) u128 { + return u128_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u128_intFromFloat_f16(a: f16) u128 { + return intFromFloat(u128, a); +} + +fn __fixunshfei(r: [*]u8, bits: usize, a: compiler_rt.f16.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f16(r[0..byte_size], compiler_rt.f16.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f16(result: []u8, a: f16) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunssfsi(a: compiler_rt.f32.Abi) callconv(.c) u32 { + return u32_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2uiz(a: f32) callconv(.{ .arm_aapcs = .{} }) u32 { + return u32_intFromFloat_f32(a); +} +pub fn u32_intFromFloat_f32(a: f32) u32 { + return intFromFloat(u32, a); +} + +fn __fixunssfdi(a: compiler_rt.f32.Abi) callconv(.c) u64 { + return u64_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2ulz(a: f32) callconv(.{ .arm_aapcs = .{} }) u64 { + return u64_intFromFloat_f32(a); +} +pub fn u64_intFromFloat_f32(a: f32) u64 { + return intFromFloat(u64, a); +} + +fn __fixunssfti(a: compiler_rt.f32.Abi) callconv(.c) u128 { + return u128_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_fixunssfti(_: compiler_rt.f32.Abi) callconv(.naked) u128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r1, r0 + \\ mov r0, sp + \\ bl %[__fixunssfti] + \\ pop {r0-r4, pc} + : + : [__fixunssfti] "X" (&__fixunssfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixunssfti] + \\ pop {r0-r4, pc} + : + : [__fixunssfti] "X" (&__fixunssfti), + ), + } +} +pub fn u128_intFromFloat_f32(a: f32) u128 { + return intFromFloat(u128, a); +} + +fn __fixunssfei(r: [*]u8, bits: usize, a: compiler_rt.f32.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f32(r[0..byte_size], compiler_rt.f32.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f32(result: []u8, a: f32) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunsdfsi(a: compiler_rt.f64.Abi) callconv(.c) u32 { + return u32_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2uiz(a: f64) callconv(.{ .arm_aapcs = .{} }) u32 { + return u32_intFromFloat_f64(a); +} +pub fn u32_intFromFloat_f64(a: f64) u32 { + return intFromFloat(u32, a); +} + +fn __fixunsdfdi(a: compiler_rt.f64.Abi) callconv(.c) u64 { + return u64_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2ulz(a: f64) callconv(.{ .arm_aapcs = .{} }) u64 { + return u64_intFromFloat_f64(a); +} +pub fn u64_intFromFloat_f64(a: f64) u64 { + return intFromFloat(u64, a); +} + +fn __fixunsdfti(a: compiler_rt.f64.Abi) callconv(.c) u128 { + return u128_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_fixunsdfti(_: compiler_rt.f64.Abi) callconv(.naked) u128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r3, r1 + \\ mov r2, r0 + \\ mov r0, sp + \\ bl %[__fixunsdfti] + \\ pop {r0-r4, pc} + : + : [__fixunsdfti] "X" (&__fixunsdfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixunsdfti] + \\ pop {r0-r4, pc} + : + : [__fixunsdfti] "X" (&__fixunsdfti), + ), + } +} +pub fn u128_intFromFloat_f64(a: f64) u128 { + return intFromFloat(u128, a); +} + +fn __fixunsdfei(r: [*]u8, bits: usize, a: compiler_rt.f64.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f64(r[0..byte_size], compiler_rt.f64.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f64(result: []u8, a: f64) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunsxfsi(a: compiler_rt.f80.Abi) callconv(.c) u32 { + return u32_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u32_intFromFloat_f80(a: f80) u32 { + return intFromFloat(u32, a); +} + +fn __fixunsxfdi(a: compiler_rt.f80.Abi) callconv(.c) u64 { + return u64_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u64_intFromFloat_f80(a: f80) u64 { + return intFromFloat(u64, a); +} + +fn __fixunsxfti(a: compiler_rt.f80.Abi) callconv(.c) u128 { + return u128_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u128_intFromFloat_f80(a: f80) u128 { + return intFromFloat(u128, a); +} + +fn __fixunsxfei(r: [*]u8, bits: usize, a: compiler_rt.f80.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f80(r[0..byte_size], compiler_rt.f80.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f80(result: []u8, a: f80) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunstfsi(a: compiler_rt.f128.Abi) callconv(.c) u32 { + return u32_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoui(a: *const f128) callconv(.c) u32 { + return u32_intFromFloat_f128(a.*); +} +pub fn u32_intFromFloat_f128(a: f128) u32 { + return intFromFloat(u32, a); +} + +fn __fixunstfdi(a: compiler_rt.f128.Abi) callconv(.c) u64 { + return u64_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoux(a: *const f128) callconv(.c) u64 { + return u64_intFromFloat_f128(a.*); +} +pub fn u64_intFromFloat_f128(a: f128) u64 { + return intFromFloat(u64, a); +} + +fn __fixunstfti(a: compiler_rt.f128.Abi) callconv(.c) u128 { + return u128_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +pub fn u128_intFromFloat_f128(a: f128) u128 { + return intFromFloat(u128, a); +} + +fn __fixunstfei(r: [*]u8, bits: usize, a: compiler_rt.f128.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f128(r[0..byte_size], compiler_rt.f128.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f128(result: []u8, a: f128) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +inline fn intFromFloat(comptime I: type, a: anytype) I { const F = @TypeOf(a); const float_bits = @typeInfo(F).float.bits; const int_bits = @typeInfo(I).int.bits; @@ -76,13 +580,14 @@ pub inline fn intFromFloat(comptime I: type, a: anytype) I { return result; } -pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, result: []u32, a: anytype) void { +inline fn bigIntFromFloat(comptime signedness: std.lang.Signedness, result: []u32, a: anytype) void { + const endian = builtin.cpu.arch.endian(); switch (result.len) { 0 => return, inline 1...4 => |limbs_len| { const I = @Int(signedness, 32 * limbs_len); const low_to_high: [limbs_len]u32 = @bitCast(@as(I, @intFromFloat(a))); - result[0..limbs_len].* = switch (@import("builtin").cpu.arch.endian()) { + result[0..limbs_len].* = switch (endian) { .little => low_to_high, .big => switch (limbs_len) { 1 => .{low_to_high[0]}, @@ -111,7 +616,6 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul }); switch (signedness) { .signed => { - const endian = @import("builtin").cpu.arch.endian(); const exponent_limb = switch (endian) { .little => exponent / 32, .big => result.len - 1 - exponent / 32, diff --git a/lib/compiler_rt/int_from_float_test.zig b/lib/compiler_rt/int_from_float_test.zig index de96954dd15474c6d9f9c5109c717b3d5b6417c2..23f04e2b88a2a01756ad608cb2d9774b54d38c25 100644 --- a/lib/compiler_rt/int_from_float_test.zig +++ b/lib/compiler_rt/int_from_float_test.zig @@ -2,1023 +2,1039 @@ const std = @import("std"); const testing = std.testing; const math = std.math; -const __fixunshfti = @import("fixunshfti.zig").__fixunshfti; -const __fixunsxfti = @import("fixunsxfti.zig").__fixunsxfti; - -// Conversion from f32 -const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; -const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; -const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; -const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; -const __fixsfti = @import("fixsfti.zig").__fixsfti; -const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; -const __fixsfei = @import("fixsfei.zig").__fixsfei; -const __fixunssfei = @import("fixunssfei.zig").__fixunssfei; - -// Conversion from f64 -const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; -const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; -const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; -const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; -const __fixdfti = @import("fixdfti.zig").__fixdfti; -const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; -const __fixdfei = @import("fixdfei.zig").__fixdfei; -const __fixunsdfei = @import("fixunsdfei.zig").__fixunsdfei; - -// Conversion from f128 -const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; -const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; -const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; -const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; -const __fixtfti = @import("fixtfti.zig").__fixtfti; -const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; - -fn test__fixsfsi(a: f32, expected: i32) !void { - const x = __fixsfsi(a); +const impl = @import("int_from_float.zig"); + +const i32_intFromFloat_f16 = impl.i32_intFromFloat_f16; +const u32_intFromFloat_f16 = impl.u32_intFromFloat_f16; +const i64_intFromFloat_f16 = impl.i64_intFromFloat_f16; +const u64_intFromFloat_f16 = impl.u64_intFromFloat_f16; +const i128_intFromFloat_f16 = impl.i128_intFromFloat_f16; +const u128_intFromFloat_f16 = impl.u128_intFromFloat_f16; +const signed_intFromFloat_f16 = impl.signed_intFromFloat_f16; +const unsigned_intFromFloat_f16 = impl.unsigned_intFromFloat_f16; + +const i32_intFromFloat_f32 = impl.i32_intFromFloat_f32; +const u32_intFromFloat_f32 = impl.u32_intFromFloat_f32; +const i64_intFromFloat_f32 = impl.i64_intFromFloat_f32; +const u64_intFromFloat_f32 = impl.u64_intFromFloat_f32; +const i128_intFromFloat_f32 = impl.i128_intFromFloat_f32; +const u128_intFromFloat_f32 = impl.u128_intFromFloat_f32; +const signed_intFromFloat_f32 = impl.signed_intFromFloat_f32; +const unsigned_intFromFloat_f32 = impl.unsigned_intFromFloat_f32; + +const i32_intFromFloat_f64 = impl.i32_intFromFloat_f64; +const u32_intFromFloat_f64 = impl.u32_intFromFloat_f64; +const i64_intFromFloat_f64 = impl.i64_intFromFloat_f64; +const u64_intFromFloat_f64 = impl.u64_intFromFloat_f64; +const i128_intFromFloat_f64 = impl.i128_intFromFloat_f64; +const u128_intFromFloat_f64 = impl.u128_intFromFloat_f64; +const signed_intFromFloat_f64 = impl.signed_intFromFloat_f64; +const unsigned_intFromFloat_f64 = impl.unsigned_intFromFloat_f64; + +const i32_intFromFloat_f80 = impl.i32_intFromFloat_f80; +const u32_intFromFloat_f80 = impl.u32_intFromFloat_f80; +const i64_intFromFloat_f80 = impl.i64_intFromFloat_f80; +const u64_intFromFloat_f80 = impl.u64_intFromFloat_f80; +const i128_intFromFloat_f80 = impl.i128_intFromFloat_f80; +const u128_intFromFloat_f80 = impl.u128_intFromFloat_f80; +const signed_intFromFloat_f80 = impl.signed_intFromFloat_f80; +const unsigned_intFromFloat_f80 = impl.unsigned_intFromFloat_f80; + +const i32_intFromFloat_f128 = impl.i32_intFromFloat_f128; +const u32_intFromFloat_f128 = impl.u32_intFromFloat_f128; +const i64_intFromFloat_f128 = impl.i64_intFromFloat_f128; +const u64_intFromFloat_f128 = impl.u64_intFromFloat_f128; +const i128_intFromFloat_f128 = impl.i128_intFromFloat_f128; +const u128_intFromFloat_f128 = impl.u128_intFromFloat_f128; +const signed_intFromFloat_f128 = impl.signed_intFromFloat_f128; +const unsigned_intFromFloat_f128 = impl.unsigned_intFromFloat_f128; + +fn test_i32_intFromFloat_f32(a: f32, expected: i32) !void { + const x = i32_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfsi(a: f32, expected: u32) !void { - const x = __fixunssfsi(a); +fn test_u32_intFromFloat_f32(a: f32, expected: u32) !void { + const x = u32_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfsi" { - try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); - - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixsfsi(-0x1.000000p+31, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfsi(-2.01, -2); - try test__fixsfsi(-2.0, -2); - try test__fixsfsi(-1.99, -1); - try test__fixsfsi(-1.0, -1); - try test__fixsfsi(-0.99, 0); - try test__fixsfsi(-0.5, 0); - - try test__fixsfsi(-math.floatMin(f32), 0); - try test__fixsfsi(0.0, 0); - try test__fixsfsi(math.floatMin(f32), 0); - try test__fixsfsi(0.5, 0); - try test__fixsfsi(0.99, 0); - try test__fixsfsi(1.0, 1); - try test__fixsfsi(1.5, 1); - try test__fixsfsi(1.99, 1); - try test__fixsfsi(2.0, 2); - try test__fixsfsi(2.01, 2); - - try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); - try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); -} - -test "fixunssfsi" { - try test__fixunssfsi(0.0, 0); - - try test__fixunssfsi(0.5, 0); - try test__fixunssfsi(0.99, 0); - try test__fixunssfsi(1.0, 1); - try test__fixunssfsi(1.5, 1); - try test__fixunssfsi(1.99, 1); - try test__fixunssfsi(2.0, 2); - try test__fixunssfsi(2.01, 2); - try test__fixunssfsi(-0.5, 0); - try test__fixunssfsi(-0.99, 0); - - try test__fixunssfsi(-1.0, 0); - try test__fixunssfsi(-1.5, 0); - try test__fixunssfsi(-1.99, 0); - try test__fixunssfsi(-2.0, 0); - try test__fixunssfsi(-2.01, 0); - - try test__fixunssfsi(0x1.000000p+31, 0x80000000); - try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunssfsi(-0x1.FFFFFEp+30, 0); - try test__fixunssfsi(-0x1.FFFFFCp+30, 0); -} - -fn test__fixsfdi(a: f32, expected: i64) !void { - const x = __fixsfdi(a); +test i32_intFromFloat_f32 { + try test_i32_intFromFloat_f32(-math.floatMax(f32), math.minInt(i32)); + + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFp+30, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i32_intFromFloat_f32(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i32_intFromFloat_f32(-2.01, -2); + try test_i32_intFromFloat_f32(-2.0, -2); + try test_i32_intFromFloat_f32(-1.99, -1); + try test_i32_intFromFloat_f32(-1.0, -1); + try test_i32_intFromFloat_f32(-0.99, 0); + try test_i32_intFromFloat_f32(-0.5, 0); + + try test_i32_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i32_intFromFloat_f32(0.0, 0); + try test_i32_intFromFloat_f32(math.floatMin(f32), 0); + try test_i32_intFromFloat_f32(0.5, 0); + try test_i32_intFromFloat_f32(0.99, 0); + try test_i32_intFromFloat_f32(1.0, 1); + try test_i32_intFromFloat_f32(1.5, 1); + try test_i32_intFromFloat_f32(1.99, 1); + try test_i32_intFromFloat_f32(2.0, 2); + try test_i32_intFromFloat_f32(2.01, 2); + + try test_i32_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i32_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f32(0x1.FFFFFFp+30, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f32(math.floatMax(f32), math.maxInt(i32)); +} + +test u32_intFromFloat_f32 { + try test_u32_intFromFloat_f32(0.0, 0); + + try test_u32_intFromFloat_f32(0.5, 0); + try test_u32_intFromFloat_f32(0.99, 0); + try test_u32_intFromFloat_f32(1.0, 1); + try test_u32_intFromFloat_f32(1.5, 1); + try test_u32_intFromFloat_f32(1.99, 1); + try test_u32_intFromFloat_f32(2.0, 2); + try test_u32_intFromFloat_f32(2.01, 2); + try test_u32_intFromFloat_f32(-0.5, 0); + try test_u32_intFromFloat_f32(-0.99, 0); + + try test_u32_intFromFloat_f32(-1.0, 0); + try test_u32_intFromFloat_f32(-1.5, 0); + try test_u32_intFromFloat_f32(-1.99, 0); + try test_u32_intFromFloat_f32(-2.0, 0); + try test_u32_intFromFloat_f32(-2.01, 0); + + try test_u32_intFromFloat_f32(0x1.000000p+31, 0x80000000); + try test_u32_intFromFloat_f32(0x1.000000p+32, 0xFFFFFFFF); + try test_u32_intFromFloat_f32(0x1.FFFFFEp+31, 0xFFFFFF00); + try test_u32_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_u32_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test_u32_intFromFloat_f32(-0x1.FFFFFEp+30, 0); + try test_u32_intFromFloat_f32(-0x1.FFFFFCp+30, 0); +} + +fn test_i64_intFromFloat_f32(a: f32, expected: i64) !void { + const x = i64_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfdi(a: f32, expected: u64) !void { - const x = __fixunssfdi(a); +fn test_u64_intFromFloat_f32(a: f32, expected: u64) !void { + const x = u64_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfdi" { - try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); - - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfdi(-2.01, -2); - try test__fixsfdi(-2.0, -2); - try test__fixsfdi(-1.99, -1); - try test__fixsfdi(-1.0, -1); - try test__fixsfdi(-0.99, 0); - try test__fixsfdi(-0.5, 0); - try test__fixsfdi(-math.floatMin(f32), 0); - try test__fixsfdi(0.0, 0); - try test__fixsfdi(math.floatMin(f32), 0); - try test__fixsfdi(0.5, 0); - try test__fixsfdi(0.99, 0); - try test__fixsfdi(1.0, 1); - try test__fixsfdi(1.5, 1); - try test__fixsfdi(1.99, 1); - try test__fixsfdi(2.0, 2); - try test__fixsfdi(2.01, 2); - - try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); -} - -test "fixunssfdi" { - try test__fixunssfdi(0.0, 0); - - try test__fixunssfdi(0.5, 0); - try test__fixunssfdi(0.99, 0); - try test__fixunssfdi(1.0, 1); - try test__fixunssfdi(1.5, 1); - try test__fixunssfdi(1.99, 1); - try test__fixunssfdi(2.0, 2); - try test__fixunssfdi(2.01, 2); - try test__fixunssfdi(-0.5, 0); - try test__fixunssfdi(-0.99, 0); - - try test__fixunssfdi(-1.0, 0); - try test__fixunssfdi(-1.5, 0); - try test__fixunssfdi(-1.99, 0); - try test__fixunssfdi(-2.0, 0); - try test__fixunssfdi(-2.01, 0); - - try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); -} - -fn test__fixsfti(a: f32, expected: i128) !void { - const x = __fixsfti(a); +test i64_intFromFloat_f32 { + try test_i64_intFromFloat_f32(-math.floatMax(f32), math.minInt(i64)); + + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.FFFFFFp+62, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i64_intFromFloat_f32(-2.01, -2); + try test_i64_intFromFloat_f32(-2.0, -2); + try test_i64_intFromFloat_f32(-1.99, -1); + try test_i64_intFromFloat_f32(-1.0, -1); + try test_i64_intFromFloat_f32(-0.99, 0); + try test_i64_intFromFloat_f32(-0.5, 0); + try test_i64_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i64_intFromFloat_f32(0.0, 0); + try test_i64_intFromFloat_f32(math.floatMin(f32), 0); + try test_i64_intFromFloat_f32(0.5, 0); + try test_i64_intFromFloat_f32(0.99, 0); + try test_i64_intFromFloat_f32(1.0, 1); + try test_i64_intFromFloat_f32(1.5, 1); + try test_i64_intFromFloat_f32(1.99, 1); + try test_i64_intFromFloat_f32(2.0, 2); + try test_i64_intFromFloat_f32(2.01, 2); + + try test_i64_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_i64_intFromFloat_f32(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f32(math.floatMax(f32), math.maxInt(i64)); +} + +test u64_intFromFloat_f32 { + try test_u64_intFromFloat_f32(0.0, 0); + + try test_u64_intFromFloat_f32(0.5, 0); + try test_u64_intFromFloat_f32(0.99, 0); + try test_u64_intFromFloat_f32(1.0, 1); + try test_u64_intFromFloat_f32(1.5, 1); + try test_u64_intFromFloat_f32(1.99, 1); + try test_u64_intFromFloat_f32(2.0, 2); + try test_u64_intFromFloat_f32(2.01, 2); + try test_u64_intFromFloat_f32(-0.5, 0); + try test_u64_intFromFloat_f32(-0.99, 0); + + try test_u64_intFromFloat_f32(-1.0, 0); + try test_u64_intFromFloat_f32(-1.5, 0); + try test_u64_intFromFloat_f32(-1.99, 0); + try test_u64_intFromFloat_f32(-2.0, 0); + try test_u64_intFromFloat_f32(-2.01, 0); + + try test_u64_intFromFloat_f32(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test_u64_intFromFloat_f32(0x1.000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f32(-0x1.FFFFFEp+62, 0x0000000000000000); + try test_u64_intFromFloat_f32(-0x1.FFFFFCp+62, 0x0000000000000000); +} + +fn test_i128_intFromFloat_f32(a: f32, expected: i128) !void { + const x = i128_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfti(a: f32, expected: u128) !void { - const x = __fixunssfti(a); +fn test_u128_intFromFloat_f32(a: f32, expected: u128) !void { + const x = u128_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfti" { - try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); - - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); - try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); - - try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfti(-0x1.000000p+31, -0x80000000); - try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfti(-2.01, -2); - try test__fixsfti(-2.0, -2); - try test__fixsfti(-1.99, -1); - try test__fixsfti(-1.0, -1); - try test__fixsfti(-0.99, 0); - try test__fixsfti(-0.5, 0); - try test__fixsfti(-math.floatMin(f32), 0); - try test__fixsfti(0.0, 0); - try test__fixsfti(math.floatMin(f32), 0); - try test__fixsfti(0.5, 0); - try test__fixsfti(0.99, 0); - try test__fixsfti(1.0, 1); - try test__fixsfti(1.5, 1); - try test__fixsfti(1.99, 1); - try test__fixsfti(2.0, 2); - try test__fixsfti(2.01, 2); - - try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); - try test__fixsfti(0x1.000000p+31, 0x80000000); - - try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); - try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); - try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); - try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); -} - -test "fixunssfti" { - try test__fixunssfti(0.0, 0); - - try test__fixunssfti(0.5, 0); - try test__fixunssfti(0.99, 0); - try test__fixunssfti(1.0, 1); - try test__fixunssfti(1.5, 1); - try test__fixunssfti(1.99, 1); - try test__fixunssfti(2.0, 2); - try test__fixunssfti(2.01, 2); - try test__fixunssfti(-0.5, 0); - try test__fixunssfti(-0.99, 0); - - try test__fixunssfti(-1.0, 0); - try test__fixunssfti(-1.5, 0); - try test__fixunssfti(-1.99, 0); - try test__fixunssfti(-2.0, 0); - try test__fixunssfti(-2.01, 0); - - try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); - try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); - try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); - try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); - - try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); - try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); - try test__fixunssfti(math.inf(f32), math.maxInt(u128)); -} - -fn test_fixsfei(comptime T: type, expected: T, a: f32) !void { +test i128_intFromFloat_f32 { + try test_i128_intFromFloat_f32(-math.floatMax(f32), math.minInt(i128)); + + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f32(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + try test_i128_intFromFloat_f32(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test_i128_intFromFloat_f32(-0x1.FFFFFFp+62, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f32(-0x1.000000p+31, -0x80000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFp+30, -0x80000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i128_intFromFloat_f32(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i128_intFromFloat_f32(-2.01, -2); + try test_i128_intFromFloat_f32(-2.0, -2); + try test_i128_intFromFloat_f32(-1.99, -1); + try test_i128_intFromFloat_f32(-1.0, -1); + try test_i128_intFromFloat_f32(-0.99, 0); + try test_i128_intFromFloat_f32(-0.5, 0); + try test_i128_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i128_intFromFloat_f32(0.0, 0); + try test_i128_intFromFloat_f32(math.floatMin(f32), 0); + try test_i128_intFromFloat_f32(0.5, 0); + try test_i128_intFromFloat_f32(0.99, 0); + try test_i128_intFromFloat_f32(1.0, 1); + try test_i128_intFromFloat_f32(1.5, 1); + try test_i128_intFromFloat_f32(1.99, 1); + try test_i128_intFromFloat_f32(2.0, 2); + try test_i128_intFromFloat_f32(2.01, 2); + + try test_i128_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i128_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i128_intFromFloat_f32(0x1.FFFFFFp+30, 0x80000000); + try test_i128_intFromFloat_f32(0x1.000000p+31, 0x80000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFFp+62, 0x8000000000000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.0000000000001p+63, 0x8000000000000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f32(math.floatMax(f32), math.maxInt(i128)); +} + +test u128_intFromFloat_f32 { + try test_u128_intFromFloat_f32(0.0, 0); + + try test_u128_intFromFloat_f32(0.5, 0); + try test_u128_intFromFloat_f32(0.99, 0); + try test_u128_intFromFloat_f32(1.0, 1); + try test_u128_intFromFloat_f32(1.5, 1); + try test_u128_intFromFloat_f32(1.99, 1); + try test_u128_intFromFloat_f32(2.0, 2); + try test_u128_intFromFloat_f32(2.01, 2); + try test_u128_intFromFloat_f32(-0.5, 0); + try test_u128_intFromFloat_f32(-0.99, 0); + + try test_u128_intFromFloat_f32(-1.0, 0); + try test_u128_intFromFloat_f32(-1.5, 0); + try test_u128_intFromFloat_f32(-1.99, 0); + try test_u128_intFromFloat_f32(-2.0, 0); + try test_u128_intFromFloat_f32(-2.01, 0); + + try test_u128_intFromFloat_f32(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test_u128_intFromFloat_f32(0x1.000000p+63, 0x8000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.000000p+127, 0x80000000000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); + + try test_u128_intFromFloat_f32(-0x1.FFFFFEp+62, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFCp+62, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFEp+126, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFCp+126, 0x0000000000000000); + try test_u128_intFromFloat_f32(math.floatMax(f32), 0xffffff00000000000000000000000000); + try test_u128_intFromFloat_f32(math.inf(f32), math.maxInt(u128)); +} + +fn test_intFromFloat_f32(comptime T: type, expected: T, a: f32) !void { const int = @typeInfo(T).int; var actual: T = undefined; _ = switch (int.signedness) { - .signed => __fixsfei, - .unsigned => __fixunssfei, - }(@ptrCast(&actual), int.bits, a); + .signed => signed_intFromFloat_f32, + .unsigned => unsigned_intFromFloat_f32, + }(@ptrCast(&actual), a); try testing.expect(expected == actual); } -test "fixsfei" { - try test_fixsfei(i256, -1 << 127, -0x1p127); - try test_fixsfei(i256, -1 << 100, -0x1p100); - try test_fixsfei(i256, -1 << 50, -0x1p50); - try test_fixsfei(i256, -1 << 1, -0x1p1); - try test_fixsfei(i256, -1 << 0, -0x1p0); - try test_fixsfei(i256, 0, 0); - try test_fixsfei(i256, 1 << 0, 0x1p0); - try test_fixsfei(i256, 1 << 1, 0x1p1); - try test_fixsfei(i256, 1 << 50, 0x1p50); - try test_fixsfei(i256, 1 << 100, 0x1p100); - try test_fixsfei(i256, 1 << 127, 0x1p127); +test signed_intFromFloat_f32 { + try test_intFromFloat_f32(i256, -1 << 127, -0x1p127); + try test_intFromFloat_f32(i256, -1 << 100, -0x1p100); + try test_intFromFloat_f32(i256, -1 << 50, -0x1p50); + try test_intFromFloat_f32(i256, -1 << 1, -0x1p1); + try test_intFromFloat_f32(i256, -1 << 0, -0x1p0); + try test_intFromFloat_f32(i256, 0, 0); + try test_intFromFloat_f32(i256, 1 << 0, 0x1p0); + try test_intFromFloat_f32(i256, 1 << 1, 0x1p1); + try test_intFromFloat_f32(i256, 1 << 50, 0x1p50); + try test_intFromFloat_f32(i256, 1 << 100, 0x1p100); + try test_intFromFloat_f32(i256, 1 << 127, 0x1p127); } -test "fixunsfei" { - try test_fixsfei(u256, 0, 0); - try test_fixsfei(u256, 1 << 0, 0x1p0); - try test_fixsfei(u256, 1 << 1, 0x1p1); - try test_fixsfei(u256, 1 << 50, 0x1p50); - try test_fixsfei(u256, 1 << 100, 0x1p100); - try test_fixsfei(u256, 1 << 127, 0x1p127); +test unsigned_intFromFloat_f32 { + try test_intFromFloat_f32(u256, 0, 0); + try test_intFromFloat_f32(u256, 1 << 0, 0x1p0); + try test_intFromFloat_f32(u256, 1 << 1, 0x1p1); + try test_intFromFloat_f32(u256, 1 << 50, 0x1p50); + try test_intFromFloat_f32(u256, 1 << 100, 0x1p100); + try test_intFromFloat_f32(u256, 1 << 127, 0x1p127); } -fn test__fixdfsi(a: f64, expected: i32) !void { - const x = __fixdfsi(a); +fn test_i32_intFromFloat_f64(a: f64, expected: i32) !void { + const x = i32_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfsi(a: f64, expected: u32) !void { - const x = __fixunsdfsi(a); +fn test_u32_intFromFloat_f64(a: f64, expected: u32) !void { + const x = u32_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfsi" { - try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); - - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixdfsi(-0x1.000000p+31, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - - try test__fixdfsi(-2.01, -2); - try test__fixdfsi(-2.0, -2); - try test__fixdfsi(-1.99, -1); - try test__fixdfsi(-1.0, -1); - try test__fixdfsi(-0.99, 0); - try test__fixdfsi(-0.5, 0); - try test__fixdfsi(-math.floatMin(f64), 0); - try test__fixdfsi(0.0, 0); - try test__fixdfsi(math.floatMin(f64), 0); - try test__fixdfsi(0.5, 0); - try test__fixdfsi(0.99, 0); - try test__fixdfsi(1.0, 1); - try test__fixdfsi(1.5, 1); - try test__fixdfsi(1.99, 1); - try test__fixdfsi(2.0, 2); - try test__fixdfsi(2.01, 2); - - try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); -} - -test "fixunsdfsi" { - try test__fixunsdfsi(0.0, 0); - - try test__fixunsdfsi(0.5, 0); - try test__fixunsdfsi(0.99, 0); - try test__fixunsdfsi(1.0, 1); - try test__fixunsdfsi(1.5, 1); - try test__fixunsdfsi(1.99, 1); - try test__fixunsdfsi(2.0, 2); - try test__fixunsdfsi(2.01, 2); - try test__fixunsdfsi(-0.5, 0); - try test__fixunsdfsi(-0.99, 0); - try test__fixunsdfsi(-1.0, 0); - try test__fixunsdfsi(-1.5, 0); - try test__fixunsdfsi(-1.99, 0); - try test__fixunsdfsi(-2.0, 0); - try test__fixunsdfsi(-2.01, 0); - - try test__fixunsdfsi(0x1.000000p+31, 0x80000000); - try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); - try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); - - try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); -} - -fn test__fixdfdi(a: f64, expected: i64) !void { - const x = __fixdfdi(a); +test i32_intFromFloat_f64 { + try test_i32_intFromFloat_f64(-math.floatMax(f64), math.minInt(i32)); + + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i32_intFromFloat_f64(-0x1.FFFFFEp+30, -0x7FFFFF80); + + try test_i32_intFromFloat_f64(-2.01, -2); + try test_i32_intFromFloat_f64(-2.0, -2); + try test_i32_intFromFloat_f64(-1.99, -1); + try test_i32_intFromFloat_f64(-1.0, -1); + try test_i32_intFromFloat_f64(-0.99, 0); + try test_i32_intFromFloat_f64(-0.5, 0); + try test_i32_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i32_intFromFloat_f64(0.0, 0); + try test_i32_intFromFloat_f64(math.floatMin(f64), 0); + try test_i32_intFromFloat_f64(0.5, 0); + try test_i32_intFromFloat_f64(0.99, 0); + try test_i32_intFromFloat_f64(1.0, 1); + try test_i32_intFromFloat_f64(1.5, 1); + try test_i32_intFromFloat_f64(1.99, 1); + try test_i32_intFromFloat_f64(2.0, 2); + try test_i32_intFromFloat_f64(2.01, 2); + + try test_i32_intFromFloat_f64(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f64(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i32_intFromFloat_f64(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f64(math.floatMax(f64), math.maxInt(i32)); +} + +test u32_intFromFloat_f64 { + try test_u32_intFromFloat_f64(0.0, 0); + + try test_u32_intFromFloat_f64(0.5, 0); + try test_u32_intFromFloat_f64(0.99, 0); + try test_u32_intFromFloat_f64(1.0, 1); + try test_u32_intFromFloat_f64(1.5, 1); + try test_u32_intFromFloat_f64(1.99, 1); + try test_u32_intFromFloat_f64(2.0, 2); + try test_u32_intFromFloat_f64(2.01, 2); + try test_u32_intFromFloat_f64(-0.5, 0); + try test_u32_intFromFloat_f64(-0.99, 0); + try test_u32_intFromFloat_f64(-1.0, 0); + try test_u32_intFromFloat_f64(-1.5, 0); + try test_u32_intFromFloat_f64(-1.99, 0); + try test_u32_intFromFloat_f64(-2.0, 0); + try test_u32_intFromFloat_f64(-2.01, 0); + + try test_u32_intFromFloat_f64(0x1.000000p+31, 0x80000000); + try test_u32_intFromFloat_f64(0x1.000000p+32, 0xFFFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFEp+31, 0xFFFFFF00); + try test_u32_intFromFloat_f64(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_u32_intFromFloat_f64(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test_u32_intFromFloat_f64(-0x1.FFFFFEp+30, 0); + try test_u32_intFromFloat_f64(-0x1.FFFFFCp+30, 0); + + try test_u32_intFromFloat_f64(0x1.FFFFFFFEp+31, 0xFFFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); +} + +fn test_i64_intFromFloat_f64(a: f64, expected: i64) !void { + const x = i64_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfdi(a: f64, expected: u64) !void { - const x = __fixunsdfdi(a); +fn test_u64_intFromFloat_f64(a: f64, expected: u64) !void { + const x = u64_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfdi" { - try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); - - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfdi(-2.01, -2); - try test__fixdfdi(-2.0, -2); - try test__fixdfdi(-1.99, -1); - try test__fixdfdi(-1.0, -1); - try test__fixdfdi(-0.99, 0); - try test__fixdfdi(-0.5, 0); - try test__fixdfdi(-math.floatMin(f64), 0); - try test__fixdfdi(0.0, 0); - try test__fixdfdi(math.floatMin(f64), 0); - try test__fixdfdi(0.5, 0); - try test__fixdfdi(0.99, 0); - try test__fixdfdi(1.0, 1); - try test__fixdfdi(1.5, 1); - try test__fixdfdi(1.99, 1); - try test__fixdfdi(2.0, 2); - try test__fixdfdi(2.01, 2); - - try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); -} - -test "fixunsdfdi" { - try test__fixunsdfdi(0.0, 0); - try test__fixunsdfdi(0.5, 0); - try test__fixunsdfdi(0.99, 0); - try test__fixunsdfdi(1.0, 1); - try test__fixunsdfdi(1.5, 1); - try test__fixunsdfdi(1.99, 1); - try test__fixunsdfdi(2.0, 2); - try test__fixunsdfdi(2.01, 2); - try test__fixunsdfdi(-0.5, 0); - try test__fixunsdfdi(-0.99, 0); - try test__fixunsdfdi(-1.0, 0); - try test__fixunsdfdi(-1.5, 0); - try test__fixunsdfdi(-1.99, 0); - try test__fixunsdfdi(-2.0, 0); - try test__fixunsdfdi(-2.01, 0); - - try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test__fixdfti(a: f64, expected: i128) !void { - const x = __fixdfti(a); +test i64_intFromFloat_f64 { + try test_i64_intFromFloat_f64(-math.floatMax(f64), math.minInt(i64)); + + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f64(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f64(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i64_intFromFloat_f64(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i64_intFromFloat_f64(-2.01, -2); + try test_i64_intFromFloat_f64(-2.0, -2); + try test_i64_intFromFloat_f64(-1.99, -1); + try test_i64_intFromFloat_f64(-1.0, -1); + try test_i64_intFromFloat_f64(-0.99, 0); + try test_i64_intFromFloat_f64(-0.5, 0); + try test_i64_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i64_intFromFloat_f64(0.0, 0); + try test_i64_intFromFloat_f64(math.floatMin(f64), 0); + try test_i64_intFromFloat_f64(0.5, 0); + try test_i64_intFromFloat_f64(0.99, 0); + try test_i64_intFromFloat_f64(1.0, 1); + try test_i64_intFromFloat_f64(1.5, 1); + try test_i64_intFromFloat_f64(1.99, 1); + try test_i64_intFromFloat_f64(2.0, 2); + try test_i64_intFromFloat_f64(2.01, 2); + + try test_i64_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f64(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f64(math.floatMax(f64), math.maxInt(i64)); +} + +test u64_intFromFloat_f64 { + try test_u64_intFromFloat_f64(0.0, 0); + try test_u64_intFromFloat_f64(0.5, 0); + try test_u64_intFromFloat_f64(0.99, 0); + try test_u64_intFromFloat_f64(1.0, 1); + try test_u64_intFromFloat_f64(1.5, 1); + try test_u64_intFromFloat_f64(1.99, 1); + try test_u64_intFromFloat_f64(2.0, 2); + try test_u64_intFromFloat_f64(2.01, 2); + try test_u64_intFromFloat_f64(-0.5, 0); + try test_u64_intFromFloat_f64(-0.99, 0); + try test_u64_intFromFloat_f64(-1.0, 0); + try test_u64_intFromFloat_f64(-1.5, 0); + try test_u64_intFromFloat_f64(-1.99, 0); + try test_u64_intFromFloat_f64(-2.0, 0); + try test_u64_intFromFloat_f64(-2.01, 0); + + try test_u64_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f64(-0x1.FFFFFEp+62, 0); + try test_u64_intFromFloat_f64(-0x1.FFFFFCp+62, 0); + + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test_u64_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test_i128_intFromFloat_f64(a: f64, expected: i128) !void { + const x = i128_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfti(a: f64, expected: u128) !void { - const x = __fixunsdfti(a); +fn test_u128_intFromFloat_f64(a: f64, expected: u128) !void { + const x = u128_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfti" { - try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); - - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfti(-2.01, -2); - try test__fixdfti(-2.0, -2); - try test__fixdfti(-1.99, -1); - try test__fixdfti(-1.0, -1); - try test__fixdfti(-0.99, 0); - try test__fixdfti(-0.5, 0); - try test__fixdfti(-math.floatMin(f64), 0); - try test__fixdfti(0.0, 0); - try test__fixdfti(math.floatMin(f64), 0); - try test__fixdfti(0.5, 0); - try test__fixdfti(0.99, 0); - try test__fixdfti(1.0, 1); - try test__fixdfti(1.5, 1); - try test__fixdfti(1.99, 1); - try test__fixdfti(2.0, 2); - try test__fixdfti(2.01, 2); - - try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); -} - -test "fixunsdfti" { - try test__fixunsdfti(0.0, 0); - - try test__fixunsdfti(0.5, 0); - try test__fixunsdfti(0.99, 0); - try test__fixunsdfti(1.0, 1); - try test__fixunsdfti(1.5, 1); - try test__fixunsdfti(1.99, 1); - try test__fixunsdfti(2.0, 2); - try test__fixunsdfti(2.01, 2); - try test__fixunsdfti(-0.5, 0); - try test__fixunsdfti(-0.99, 0); - try test__fixunsdfti(-1.0, 0); - try test__fixunsdfti(-1.5, 0); - try test__fixunsdfti(-1.99, 0); - try test__fixunsdfti(-2.0, 0); - try test__fixunsdfti(-2.01, 0); - - try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfti(-0x1.FFFFFEp+62, 0); - try test__fixunsdfti(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test_fixdfei(comptime T: type, expected: T, a: f64) !void { +test i128_intFromFloat_f64 { + try test_i128_intFromFloat_f64(-math.floatMax(f64), math.minInt(i128)); + + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f64(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test_i128_intFromFloat_f64(-0x1.0000000000001p+63, -0x8000000000000800); + try test_i128_intFromFloat_f64(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i128_intFromFloat_f64(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f64(-2.01, -2); + try test_i128_intFromFloat_f64(-2.0, -2); + try test_i128_intFromFloat_f64(-1.99, -1); + try test_i128_intFromFloat_f64(-1.0, -1); + try test_i128_intFromFloat_f64(-0.99, 0); + try test_i128_intFromFloat_f64(-0.5, 0); + try test_i128_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i128_intFromFloat_f64(0.0, 0); + try test_i128_intFromFloat_f64(math.floatMin(f64), 0); + try test_i128_intFromFloat_f64(0.5, 0); + try test_i128_intFromFloat_f64(0.99, 0); + try test_i128_intFromFloat_f64(1.0, 1); + try test_i128_intFromFloat_f64(1.5, 1); + try test_i128_intFromFloat_f64(1.99, 1); + try test_i128_intFromFloat_f64(2.0, 2); + try test_i128_intFromFloat_f64(2.01, 2); + + try test_i128_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f64(0x1.0000000000001p+63, 0x8000000000000800); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f64(math.floatMax(f64), math.maxInt(i128)); +} + +test u128_intFromFloat_f64 { + try test_u128_intFromFloat_f64(0.0, 0); + + try test_u128_intFromFloat_f64(0.5, 0); + try test_u128_intFromFloat_f64(0.99, 0); + try test_u128_intFromFloat_f64(1.0, 1); + try test_u128_intFromFloat_f64(1.5, 1); + try test_u128_intFromFloat_f64(1.99, 1); + try test_u128_intFromFloat_f64(2.0, 2); + try test_u128_intFromFloat_f64(2.01, 2); + try test_u128_intFromFloat_f64(-0.5, 0); + try test_u128_intFromFloat_f64(-0.99, 0); + try test_u128_intFromFloat_f64(-1.0, 0); + try test_u128_intFromFloat_f64(-1.5, 0); + try test_u128_intFromFloat_f64(-1.99, 0); + try test_u128_intFromFloat_f64(-2.0, 0); + try test_u128_intFromFloat_f64(-2.01, 0); + + try test_u128_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u128_intFromFloat_f64(-0x1.FFFFFEp+62, 0); + try test_u128_intFromFloat_f64(-0x1.FFFFFCp+62, 0); + + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test_u128_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); + try test_u128_intFromFloat_f64(0x1.0000000000000p+127, 0x80000000000000000000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_u128_intFromFloat_f64(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_u128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test_intFromFloat_f64(comptime T: type, expected: T, a: f64) !void { const int = @typeInfo(T).int; var actual: T = undefined; _ = switch (int.signedness) { - .signed => __fixdfei, - .unsigned => __fixunsdfei, - }(@ptrCast(&actual), int.bits, a); + .signed => signed_intFromFloat_f64, + .unsigned => unsigned_intFromFloat_f64, + }(@ptrCast(&actual), a); try testing.expect(expected == actual); } -test "fixdfei" { - try test_fixdfei(i256, -1 << 255, -0x1p255); - try test_fixdfei(i256, -1 << 127, -0x1p127); - try test_fixdfei(i256, -1 << 100, -0x1p100); - try test_fixdfei(i256, -1 << 50, -0x1p50); - try test_fixdfei(i256, -1 << 1, -0x1p1); - try test_fixdfei(i256, -1 << 0, -0x1p0); - try test_fixdfei(i256, 0, 0); - try test_fixdfei(i256, 1 << 0, 0x1p0); - try test_fixdfei(i256, 1 << 1, 0x1p1); - try test_fixdfei(i256, 1 << 50, 0x1p50); - try test_fixdfei(i256, 1 << 100, 0x1p100); - try test_fixdfei(i256, 1 << 127, 0x1p127); - try test_fixdfei(i256, 1 << 254, 0x1p254); -} - -test "fixundfei" { - try test_fixdfei(u256, 0, 0); - try test_fixdfei(u256, 1 << 0, 0x1p0); - try test_fixdfei(u256, 1 << 1, 0x1p1); - try test_fixdfei(u256, 1 << 50, 0x1p50); - try test_fixdfei(u256, 1 << 100, 0x1p100); - try test_fixdfei(u256, 1 << 127, 0x1p127); - try test_fixdfei(u256, 1 << 255, 0x1p255); -} - -fn test__fixtfsi(a: f128, expected: i32) !void { - const x = __fixtfsi(a); - try testing.expect(x == expected); +test signed_intFromFloat_f64 { + try test_intFromFloat_f64(i256, -1 << 255, -0x1p255); + try test_intFromFloat_f64(i256, -1 << 127, -0x1p127); + try test_intFromFloat_f64(i256, -1 << 100, -0x1p100); + try test_intFromFloat_f64(i256, -1 << 50, -0x1p50); + try test_intFromFloat_f64(i256, -1 << 1, -0x1p1); + try test_intFromFloat_f64(i256, -1 << 0, -0x1p0); + try test_intFromFloat_f64(i256, 0, 0); + try test_intFromFloat_f64(i256, 1 << 0, 0x1p0); + try test_intFromFloat_f64(i256, 1 << 1, 0x1p1); + try test_intFromFloat_f64(i256, 1 << 50, 0x1p50); + try test_intFromFloat_f64(i256, 1 << 100, 0x1p100); + try test_intFromFloat_f64(i256, 1 << 127, 0x1p127); + try test_intFromFloat_f64(i256, 1 << 254, 0x1p254); } -fn test__fixunstfsi(a: f128, expected: u32) !void { - const x = __fixunstfsi(a); - try testing.expect(x == expected); +test unsigned_intFromFloat_f64 { + try test_intFromFloat_f64(u256, 0, 0); + try test_intFromFloat_f64(u256, 1 << 0, 0x1p0); + try test_intFromFloat_f64(u256, 1 << 1, 0x1p1); + try test_intFromFloat_f64(u256, 1 << 50, 0x1p50); + try test_intFromFloat_f64(u256, 1 << 100, 0x1p100); + try test_intFromFloat_f64(u256, 1 << 127, 0x1p127); + try test_intFromFloat_f64(u256, 1 << 255, 0x1p255); } -test "fixtfsi" { - try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); - - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixtfsi(-0x1.000000p+31, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfsi(-2.01, -2); - try test__fixtfsi(-2.0, -2); - try test__fixtfsi(-1.99, -1); - try test__fixtfsi(-1.0, -1); - try test__fixtfsi(-0.99, 0); - try test__fixtfsi(-0.5, 0); - try test__fixtfsi(-math.floatMin(f32), 0); - try test__fixtfsi(0.0, 0); - try test__fixtfsi(math.floatMin(f32), 0); - try test__fixtfsi(0.5, 0); - try test__fixtfsi(0.99, 0); - try test__fixtfsi(1.0, 1); - try test__fixtfsi(1.5, 1); - try test__fixtfsi(1.99, 1); - try test__fixtfsi(2.0, 2); - try test__fixtfsi(2.01, 2); - - try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); -} - -test "fixunstfsi" { - try test__fixunstfsi(math.inf(f128), 0xffffffff); - try test__fixunstfsi(0, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); - try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); - try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); - try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); - try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); - - try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); -} - -fn test__fixtfdi(a: f128, expected: i64) !void { - const x = __fixtfdi(a); +fn test_i32_intFromFloat_f128(a: f128, expected: i32) !void { + const x = i32_intFromFloat_f128(a); try testing.expect(x == expected); } -fn test__fixunstfdi(a: f128, expected: u64) !void { - const x = __fixunstfdi(a); +fn test_u32_intFromFloat_f128(a: f128, expected: u32) !void { + const x = u32_intFromFloat_f128(a); try testing.expect(x == expected); } -test "fixtfdi" { - try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); - - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); - try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); - - try test__fixtfdi(-0x1.000000p+31, -0x80000000); - try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfdi(-2.01, -2); - try test__fixtfdi(-2.0, -2); - try test__fixtfdi(-1.99, -1); - try test__fixtfdi(-1.0, -1); - try test__fixtfdi(-0.99, 0); - try test__fixtfdi(-0.5, 0); - try test__fixtfdi(-math.floatMin(f64), 0); - try test__fixtfdi(0.0, 0); - try test__fixtfdi(math.floatMin(f64), 0); - try test__fixtfdi(0.5, 0); - try test__fixtfdi(0.99, 0); - try test__fixtfdi(1.0, 1); - try test__fixtfdi(1.5, 1); - try test__fixtfdi(1.99, 1); - try test__fixtfdi(2.0, 2); - try test__fixtfdi(2.01, 2); - - try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfdi(0x1.000000p+31, 0x80000000); - - try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); -} - -test "fixunstfdi" { - try test__fixunstfdi(0.0, 0); - - try test__fixunstfdi(0.5, 0); - try test__fixunstfdi(0.99, 0); - try test__fixunstfdi(1.0, 1); - try test__fixunstfdi(1.5, 1); - try test__fixunstfdi(1.99, 1); - try test__fixunstfdi(2.0, 2); - try test__fixunstfdi(2.01, 2); - try test__fixunstfdi(-0.5, 0); - try test__fixunstfdi(-0.99, 0); - try test__fixunstfdi(-1.0, 0); - try test__fixunstfdi(-1.5, 0); - try test__fixunstfdi(-1.99, 0); - try test__fixunstfdi(-2.0, 0); - try test__fixunstfdi(-2.01, 0); - - try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunstfdi(-0x1.FFFFFEp+62, 0); - try test__fixunstfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); - try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); - try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); - - try test__fixunstfdi(-0x1.0000000000000000p+63, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); -} - -fn test__fixtfti(a: f128, expected: i128) !void { - const x = __fixtfti(a); - try testing.expect(x == expected); +test i32_intFromFloat_f128 { + try test_i32_intFromFloat_f128(-math.floatMax(f128), math.minInt(i32)); + + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i32_intFromFloat_f128(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i32_intFromFloat_f128(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i32_intFromFloat_f128(-2.01, -2); + try test_i32_intFromFloat_f128(-2.0, -2); + try test_i32_intFromFloat_f128(-1.99, -1); + try test_i32_intFromFloat_f128(-1.0, -1); + try test_i32_intFromFloat_f128(-0.99, 0); + try test_i32_intFromFloat_f128(-0.5, 0); + try test_i32_intFromFloat_f128(-math.floatMin(f32), 0); + try test_i32_intFromFloat_f128(0.0, 0); + try test_i32_intFromFloat_f128(math.floatMin(f32), 0); + try test_i32_intFromFloat_f128(0.5, 0); + try test_i32_intFromFloat_f128(0.99, 0); + try test_i32_intFromFloat_f128(1.0, 1); + try test_i32_intFromFloat_f128(1.5, 1); + try test_i32_intFromFloat_f128(1.99, 1); + try test_i32_intFromFloat_f128(2.0, 2); + try test_i32_intFromFloat_f128(2.01, 2); + + try test_i32_intFromFloat_f128(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i32_intFromFloat_f128(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f128(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i32_intFromFloat_f128(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f128(math.floatMax(f128), math.maxInt(i32)); } -fn test__fixunstfti(a: f128, expected: u128) !void { - const x = __fixunstfti(a); - try testing.expect(x == expected); +test u32_intFromFloat_f128 { + try test_u32_intFromFloat_f128(math.inf(f128), 0xffffffff); + try test_u32_intFromFloat_f128(0, 0x0); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+5, 0x24); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp-3, 0x0); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+20, 0x123456); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+40, 0xffffffff); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+256, 0xffffffff); + try test_u32_intFromFloat_f128(-0x1.23456789abcdefp+3, 0x0); + + try test_u32_intFromFloat_f128(0x1p+32, 0xFFFFFFFF); } -test "fixtfti" { - try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); - - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); +fn test_i64_intFromFloat_f128(a: f128, expected: i64) !void { + const x = i64_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(-2.01, -2); - try test__fixtfti(-2.0, -2); - try test__fixtfti(-1.99, -1); - try test__fixtfti(-1.0, -1); - try test__fixtfti(-0.99, 0); - try test__fixtfti(-0.5, 0); - try test__fixtfti(-math.floatMin(f128), 0); - try test__fixtfti(0.0, 0); - try test__fixtfti(math.floatMin(f128), 0); - try test__fixtfti(0.5, 0); - try test__fixtfti(0.99, 0); - try test__fixtfti(1.0, 1); - try test__fixtfti(1.5, 1); - try test__fixtfti(1.99, 1); - try test__fixtfti(2.0, 2); - try test__fixtfti(2.01, 2); +fn test_u64_intFromFloat_f128(a: f128, expected: u64) !void { + const x = u64_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); +test i64_intFromFloat_f128 { + try test_i64_intFromFloat_f128(-math.floatMax(f128), math.minInt(i64)); + + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f128(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f128(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i64_intFromFloat_f128(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + try test_i64_intFromFloat_f128(-0x1.000000p+31, -0x80000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i64_intFromFloat_f128(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i64_intFromFloat_f128(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i64_intFromFloat_f128(-2.01, -2); + try test_i64_intFromFloat_f128(-2.0, -2); + try test_i64_intFromFloat_f128(-1.99, -1); + try test_i64_intFromFloat_f128(-1.0, -1); + try test_i64_intFromFloat_f128(-0.99, 0); + try test_i64_intFromFloat_f128(-0.5, 0); + try test_i64_intFromFloat_f128(-math.floatMin(f64), 0); + try test_i64_intFromFloat_f128(0.0, 0); + try test_i64_intFromFloat_f128(math.floatMin(f64), 0); + try test_i64_intFromFloat_f128(0.5, 0); + try test_i64_intFromFloat_f128(0.99, 0); + try test_i64_intFromFloat_f128(1.0, 1); + try test_i64_intFromFloat_f128(1.5, 1); + try test_i64_intFromFloat_f128(1.99, 1); + try test_i64_intFromFloat_f128(2.0, 2); + try test_i64_intFromFloat_f128(2.01, 2); + + try test_i64_intFromFloat_f128(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i64_intFromFloat_f128(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i64_intFromFloat_f128(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i64_intFromFloat_f128(0x1.000000p+31, 0x80000000); + + try test_i64_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f128(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f128(math.floatMax(f128), math.maxInt(i64)); +} - try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); +test u64_intFromFloat_f128 { + try test_u64_intFromFloat_f128(0.0, 0); + + try test_u64_intFromFloat_f128(0.5, 0); + try test_u64_intFromFloat_f128(0.99, 0); + try test_u64_intFromFloat_f128(1.0, 1); + try test_u64_intFromFloat_f128(1.5, 1); + try test_u64_intFromFloat_f128(1.99, 1); + try test_u64_intFromFloat_f128(2.0, 2); + try test_u64_intFromFloat_f128(2.01, 2); + try test_u64_intFromFloat_f128(-0.5, 0); + try test_u64_intFromFloat_f128(-0.99, 0); + try test_u64_intFromFloat_f128(-1.0, 0); + try test_u64_intFromFloat_f128(-1.5, 0); + try test_u64_intFromFloat_f128(-1.99, 0); + try test_u64_intFromFloat_f128(-2.0, 0); + try test_u64_intFromFloat_f128(-2.01, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f128(-0x1.FFFFFEp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFCp+62, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); + try test_u64_intFromFloat_f128(0x1.0000000000000002p+63, 0x8000000000000001); + try test_u64_intFromFloat_f128(0x1.0000000000000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); + try test_u64_intFromFloat_f128(0x1p+64, 0xFFFFFFFFFFFFFFFF); + + try test_u64_intFromFloat_f128(-0x1.0000000000000000p+63, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFFFCp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFFF8p+62, 0); +} - try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); +fn test_i128_intFromFloat_f128(a: f128, expected: i128) !void { + const x = i128_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); +fn test_u128_intFromFloat_f128(a: f128, expected: u128) !void { + const x = u128_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); +test i128_intFromFloat_f128 { + try test_i128_intFromFloat_f128(-math.floatMax(f128), math.minInt(i128)); + + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f128(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test_i128_intFromFloat_f128(-0x1.0000000000001p+63, -0x8000000000000800); + try test_i128_intFromFloat_f128(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i128_intFromFloat_f128(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f128(-2.01, -2); + try test_i128_intFromFloat_f128(-2.0, -2); + try test_i128_intFromFloat_f128(-1.99, -1); + try test_i128_intFromFloat_f128(-1.0, -1); + try test_i128_intFromFloat_f128(-0.99, 0); + try test_i128_intFromFloat_f128(-0.5, 0); + try test_i128_intFromFloat_f128(-math.floatMin(f128), 0); + try test_i128_intFromFloat_f128(0.0, 0); + try test_i128_intFromFloat_f128(math.floatMin(f128), 0); + try test_i128_intFromFloat_f128(0.5, 0); + try test_i128_intFromFloat_f128(0.99, 0); + try test_i128_intFromFloat_f128(1.0, 1); + try test_i128_intFromFloat_f128(1.5, 1); + try test_i128_intFromFloat_f128(1.99, 1); + try test_i128_intFromFloat_f128(2.0, 2); + try test_i128_intFromFloat_f128(2.01, 2); + + try test_i128_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f128(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f128(0x1.0000000000001p+63, 0x8000000000000800); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f128(math.floatMax(f128), math.maxInt(i128)); } -test "fixunstfti" { - try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); +test u128_intFromFloat_f128 { + try test_u128_intFromFloat_f128(math.inf(f128), 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0.0, 0); + try test_u128_intFromFloat_f128(0.0, 0); - try test__fixunstfti(0.5, 0); - try test__fixunstfti(0.99, 0); - try test__fixunstfti(1.0, 1); - try test__fixunstfti(1.5, 1); - try test__fixunstfti(1.99, 1); - try test__fixunstfti(2.0, 2); - try test__fixunstfti(2.01, 2); - try test__fixunstfti(-0.01, 0); - try test__fixunstfti(-0.99, 0); + try test_u128_intFromFloat_f128(0.5, 0); + try test_u128_intFromFloat_f128(0.99, 0); + try test_u128_intFromFloat_f128(1.0, 1); + try test_u128_intFromFloat_f128(1.5, 1); + try test_u128_intFromFloat_f128(1.99, 1); + try test_u128_intFromFloat_f128(2.0, 2); + try test_u128_intFromFloat_f128(2.01, 2); + try test_u128_intFromFloat_f128(-0.01, 0); + try test_u128_intFromFloat_f128(-0.99, 0); - try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1p+128, 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); } -fn test__fixunshfti(a: f16, expected: u128) !void { - const x = __fixunshfti(a); +fn test_u128_intFromFloat_f16(a: f16, expected: u128) !void { + const x = impl.u128_intFromFloat_f16(a); try testing.expect(x == expected); } -test "fixunshfti for f16" { - try test__fixunshfti(math.inf(f16), math.maxInt(u128)); - try test__fixunshfti(math.floatMax(f16), 65504); +test u128_intFromFloat_f16 { + try test_u128_intFromFloat_f16(math.inf(f16), math.maxInt(u128)); + try test_u128_intFromFloat_f16(math.floatMax(f16), 65504); } -fn test__fixunsxfti(a: f80, expected: u128) !void { - const x = __fixunsxfti(a); +fn test_u128_intFromFloat_f80(a: f80, expected: u128) !void { + const x = impl.u128_intFromFloat_f80(a); try testing.expect(x == expected); } -test "fixunsxfti for f80" { - try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); - try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); - try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); +test u128_intFromFloat_f80 { + try test_u128_intFromFloat_f80(math.inf(f80), math.maxInt(u128)); + try test_u128_intFromFloat_f80(math.floatMax(f80), math.maxInt(u128)); + try test_u128_intFromFloat_f80(math.maxInt(u64), math.maxInt(u64)); } diff --git a/lib/compiler_rt/limb64.zig b/lib/compiler_rt/limb64.zig index bfe4c441f0525b2e7f5e858e3fa98f81a2e9c865..1d41c0ff1f673c4822b69ccbf0eee69faad19b51 100644 --- a/lib/compiler_rt/limb64.zig +++ b/lib/compiler_rt/limb64.zig @@ -6,7 +6,7 @@ const minInt = std.math.minInt; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const endian = builtin.cpu.arch.endian(); diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig index da3757d8224c2ab62e88affd269170b5c64cae6b..8b2937921d5998941e7731ac8decce71f60c85cb 100644 --- a/lib/compiler_rt/log.zig +++ b/lib/compiler_rt/log.zig @@ -11,26 +11,29 @@ const expectEqual = std.testing.expectEqual; const expectApproxEqRel = std.testing.expectApproxEqRel; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__logh, "__logh"); symbol(&logf, "logf"); symbol(&log, "log"); symbol(&__logx, "__logx"); - if (compiler_rt.want_ppc_abi) { - symbol(&logq, "logf128"); - } - symbol(&logq, "logq"); + symbol(&logq, "logf128"); symbol(&logl, "logl"); } -pub fn __logh(a: f16) callconv(.c) f16 { +fn __logh(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(logf(a)); + return @floatCast(log_f32(a)); } -pub fn logf(x_: f32) callconv(.c) f32 { +fn logf(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log_f32(x_: f32) f32 { const ln2_hi: f32 = 6.9313812256e-01; const ln2_lo: f32 = 9.0580006145e-06; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -82,7 +85,10 @@ pub fn logf(x_: f32) callconv(.c) f32 { return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; } -pub fn log(x: f64) callconv(.c) f64 { +fn log(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log_f64(x: f64) f64 { const poly1 = [_]f64{ -0x1p-1, 0x1.5555555555577p-2, @@ -432,11 +438,17 @@ pub fn log(x: f64) callconv(.c) f64 { return @bitCast(y); } -pub fn __logx(a: f80) callconv(.c) f80 { +fn __logx(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(logq(a)); + return @floatCast(log_f128(a)); } +fn logq(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -449,7 +461,7 @@ pub fn __logx(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.96%, worst case <= 0.528 ulp -pub fn logq(x: f128) callconv(.c) f128 { +pub fn log_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -626,123 +638,123 @@ pub fn logq(x: f128) callconv(.c) f128 { pub fn logl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log(x), - 80 => return __logx(x), - 128 => return logq(x), - else => @compileError("unreachable"), + 64 => return log_f64(x), + 80 => return log_f80(x), + 128 => return log_f128(x), + else => comptime unreachable, } } test "logf() special" { - try expectEqual(logf(0.0), -math.inf(f32)); - try expectEqual(logf(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(logf(1.0))); - try expectEqual(logf(math.e), 1.0); - try expectEqual(logf(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(logf(-1.0))); - try expect(math.isNan(logf(-math.inf(f32)))); - try expect(math.isNan(logf(math.nan(f32)))); - try expect(math.isNan(logf(math.snan(f32)))); + try expectEqual(log_f32(0.0), -math.inf(f32)); + try expectEqual(log_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log_f32(1.0))); + try expectEqual(log_f32(math.e), 1.0); + try expectEqual(log_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log_f32(-1.0))); + try expect(math.isNan(log_f32(-math.inf(f32)))); + try expect(math.isNan(log_f32(math.nan(f32)))); + try expect(math.isNan(log_f32(math.snan(f32)))); } test "logf() sanity" { - try expect(math.isNan(logf(-0x1.0223a0p+3))); - try expectEqual(logf(0x1.161868p+2), 0x1.7815b0p+0); - try expect(math.isNan(logf(-0x1.0c34b4p+3))); - try expect(math.isNan(logf(-0x1.a206f0p+2))); - try expectEqual(logf(0x1.288bbcp+3), 0x1.1cfcd6p+1); - try expectEqual(logf(0x1.52efd0p-1), -0x1.a6694cp-2); - try expect(math.isNan(logf(-0x1.a05cc8p-2))); - try expectEqual(logf(0x1.1f9efap-1), -0x1.2742bap-1); - try expectEqual(logf(0x1.8c5db0p-1), -0x1.062160p-2); - try expect(math.isNan(logf(-0x1.5b86eap-1))); + try expect(math.isNan(log_f32(-0x1.0223a0p+3))); + try expectEqual(log_f32(0x1.161868p+2), 0x1.7815b0p+0); + try expect(math.isNan(log_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log_f32(-0x1.a206f0p+2))); + try expectEqual(log_f32(0x1.288bbcp+3), 0x1.1cfcd6p+1); + try expectEqual(log_f32(0x1.52efd0p-1), -0x1.a6694cp-2); + try expect(math.isNan(log_f32(-0x1.a05cc8p-2))); + try expectEqual(log_f32(0x1.1f9efap-1), -0x1.2742bap-1); + try expectEqual(log_f32(0x1.8c5db0p-1), -0x1.062160p-2); + try expect(math.isNan(log_f32(-0x1.5b86eap-1))); } test "logf() boundary" { - try expectEqual(logf(0x1.fffffep+127), 0x1.62e430p+6); // Max input value - try expectEqual(logf(0x1p-149), -0x1.9d1da0p+6); // Min positive input value - try expect(math.isNan(logf(-0x1p-149))); // Min negative input value - try expectEqual(logf(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0 - try expectEqual(logf(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0 - try expectEqual(logf(0x1p-126), -0x1.5d58a0p+6); // First subnormal - try expect(math.isNan(logf(-0x1p-126))); // First negative subnormal + try expectEqual(log_f32(0x1.fffffep+127), 0x1.62e430p+6); // Max input value + try expectEqual(log_f32(0x1p-149), -0x1.9d1da0p+6); // Min positive input value + try expect(math.isNan(log_f32(-0x1p-149))); // Min negative input value + try expectEqual(log_f32(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0 + try expectEqual(log_f32(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0 + try expectEqual(log_f32(0x1p-126), -0x1.5d58a0p+6); // First subnormal + try expect(math.isNan(log_f32(-0x1p-126))); // First negative subnormal } test "log() special" { - try expectEqual(log(0.0), -math.inf(f64)); - try expectEqual(log(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log(1.0))); - try expectEqual(log(math.e), 1.0); - try expectEqual(log(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log(-1.0))); - try expect(math.isNan(log(-math.inf(f64)))); - try expect(math.isNan(log(math.nan(f64)))); - try expect(math.isNan(log(math.snan(f64)))); + try expectEqual(log_f64(0.0), -math.inf(f64)); + try expectEqual(log_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log_f64(1.0))); + try expectEqual(log_f64(math.e), 1.0); + try expectEqual(log_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log_f64(-1.0))); + try expect(math.isNan(log_f64(-math.inf(f64)))); + try expect(math.isNan(log_f64(math.nan(f64)))); + try expect(math.isNan(log_f64(math.snan(f64)))); } test "log() sanity" { - try expect(math.isNan(log(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0); - try expect(math.isNan(log(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1); - try expectEqual(log(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2); - try expect(math.isNan(log(-0x1.a05cc754481d1p-2))); - try expectEqual(log(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1); - try expectEqual(log(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2); - try expect(math.isNan(log(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log_f64(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0); + try expect(math.isNan(log_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log_f64(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1); + try expectEqual(log_f64(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2); + try expect(math.isNan(log_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log_f64(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1); + try expectEqual(log_f64(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2); + try expect(math.isNan(log_f64(-0x1.5b86ea8118a0ep-1))); } test "log() boundary" { - try expectEqual(log(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value - try expectEqual(log(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value - try expect(math.isNan(log(-0x1p-1074))); // Min negative input value - try expectEqual(log(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0 - try expectEqual(log(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0 - try expectEqual(log(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal - try expect(math.isNan(log(-0x1p-1022))); // First negative subnormal + try expectEqual(log_f64(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value + try expectEqual(log_f64(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value + try expect(math.isNan(log_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log_f64(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0 + try expectEqual(log_f64(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0 + try expectEqual(log_f64(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal + try expect(math.isNan(log_f64(-0x1p-1022))); // First negative subnormal } test "logq() special" { - try expectEqual(logq(0.0), -math.inf(f128)); - try expectEqual(logq(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(logq(1.0))); + try expectEqual(log_f128(0.0), -math.inf(f128)); + try expectEqual(log_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log_f128(1.0))); // Sadly, the rounding gods decided that 0.9999999999999999999999999999999999 - // is the correctly rounded value of logq(math.e) - try expectApproxEqRel(logq(math.e), 1.0, math.floatEpsAt(f128, 1.0)); - try expectEqual(logq(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(logq(-1.0))); - try expect(math.isNan(logq(-math.inf(f128)))); - try expect(math.isNan(logq(math.nan(f128)))); - try expect(math.isNan(logq(math.snan(f128)))); + // is the correctly rounded value of log_f128(math.e) + try expectApproxEqRel(log_f128(math.e), 1.0, math.floatEpsAt(f128, 1.0)); + try expectEqual(log_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log_f128(-1.0))); + try expect(math.isNan(log_f128(-math.inf(f128)))); + try expect(math.isNan(log_f128(math.nan(f128)))); + try expect(math.isNan(log_f128(math.snan(f128)))); } test "logq() boundary" { - try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp16383), 0x1.62e42fefa39ef35793c7673007e6p13); // Max input value - try expectEqual(logq(0x1p-16494), -0x1.6546282207802c89d24d65e96274p13); // Min positive input value - try expect(math.isNan(logq(-0x1p-16494))); // Min negative input value - try expectEqual(logq(0x1.0000000000000000000000000001p0), 0x1.ffffffffffffffffffffffffffffp-113); // Last value before result reaches +0 - try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp-1), -0x1p-113); // Last value before result reaches -0 - try expectEqual(logq(0x1p-16382), -0x1.62d918ce2421d65ff90ac8f4ce66p13); // First subnormal - try expect(math.isNan(logq(-0x1p-16382))); // First negative subnormal + try expectEqual(log_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1.62e42fefa39ef35793c7673007e6p13); // Max input value + try expectEqual(log_f128(0x1p-16494), -0x1.6546282207802c89d24d65e96274p13); // Min positive input value + try expect(math.isNan(log_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log_f128(0x1.0000000000000000000000000001p0), 0x1.ffffffffffffffffffffffffffffp-113); // Last value before result reaches +0 + try expectEqual(log_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1p-113); // Last value before result reaches -0 + try expectEqual(log_f128(0x1p-16382), -0x1.62d918ce2421d65ff90ac8f4ce66p13); // First subnormal + try expect(math.isNan(log_f128(-0x1p-16382))); // First negative subnormal } test "logq() sanity" { - try expectEqual(logq(4.151135979023751199079583784623537e-4), -7.7869583453055243113993340258295346e0); - try expectEqual(logq(9.614234245933828353176667689130293e-14), -2.9972946567656004014786271559909435e1); - try expectEqual(logq(1.012889803704721484375e13), 2.9946413646144315985379677542014356e1); - try expectEqual(logq(2.397741857206453154086912e24), 5.613656963346284538829358703465392e1); - try expectEqual(logq(3.442377567808290806386655232e27), 6.3405959896920645453203836625419693e1); - try expectEqual(logq(1.0689155158234028407981544637594257e-8), -1.835403614606774451014272772421113e1); - try expectEqual(logq(1.4813913545768791536741499811327596e-10), -2.263286917934202003739900705050399e1); - try expectEqual(logq(4.518948965781299591064453125e10), 2.453413036705097282892685629562292e1); - try expectEqual(logq(1.200355637363589375e14), 3.2418809179272977400408325788186897e1); - try expectEqual(logq(6.6145398293682003021240234375e9), 2.261253606737223221601998075023261e1); - try expectEqual(logq(5.16179116383965741056e20), 4.7692985503915646405875629300054525e1); + try expectEqual(log_f128(4.151135979023751199079583784623537e-4), -7.7869583453055243113993340258295346e0); + try expectEqual(log_f128(9.614234245933828353176667689130293e-14), -2.9972946567656004014786271559909435e1); + try expectEqual(log_f128(1.012889803704721484375e13), 2.9946413646144315985379677542014356e1); + try expectEqual(log_f128(2.397741857206453154086912e24), 5.613656963346284538829358703465392e1); + try expectEqual(log_f128(3.442377567808290806386655232e27), 6.3405959896920645453203836625419693e1); + try expectEqual(log_f128(1.0689155158234028407981544637594257e-8), -1.835403614606774451014272772421113e1); + try expectEqual(log_f128(1.4813913545768791536741499811327596e-10), -2.263286917934202003739900705050399e1); + try expectEqual(log_f128(4.518948965781299591064453125e10), 2.453413036705097282892685629562292e1); + try expectEqual(log_f128(1.200355637363589375e14), 3.2418809179272977400408325788186897e1); + try expectEqual(log_f128(6.6145398293682003021240234375e9), 2.261253606737223221601998075023261e1); + try expectEqual(log_f128(5.16179116383965741056e20), 4.7692985503915646405875629300054525e1); // testing near 1 - try expectEqual(logq(1.026586845186097528392910049888087e0), 2.6239557099466251374193777672800004e-2); - try expectEqual(logq(9.878220373715243107115568932385941e-1), -1.2252721576456821219120474521538944e-2); - try expectEqual(logq(9.417921077517196685541245315675951e-1), -5.997072116986790367958922503195352e-2); - try expectEqual(logq(1.043095786320424537962914257605007e0), 4.219300911769055080390811808602425e-2); - try expectEqual(logq(1.019043049323190694932517175175235e0), 1.8863999985309781522599012445793722e-2); + try expectEqual(log_f128(1.026586845186097528392910049888087e0), 2.6239557099466251374193777672800004e-2); + try expectEqual(log_f128(9.878220373715243107115568932385941e-1), -1.2252721576456821219120474521538944e-2); + try expectEqual(log_f128(9.417921077517196685541245315675951e-1), -5.997072116986790367958922503195352e-2); + try expectEqual(log_f128(1.043095786320424537962914257605007e0), 4.219300911769055080390811808602425e-2); + try expectEqual(log_f128(1.019043049323190694932517175175235e0), 1.8863999985309781522599012445793722e-2); } diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig index 18479d534a347721c842b682228f29688213909c..0813c1ae7c0dc6d71ae7aa2699f17e05bdffe039 100644 --- a/lib/compiler_rt/log10.zig +++ b/lib/compiler_rt/log10.zig @@ -18,19 +18,22 @@ comptime { symbol(&log10f, "log10f"); symbol(&log10, "log10"); symbol(&__log10x, "__log10x"); - if (compiler_rt.want_ppc_abi) { - symbol(&log10q, "log10f128"); - } - symbol(&log10q, "log10q"); + symbol(&log10q, "log10f128"); symbol(&log10l, "log10l"); } -pub fn __log10h(a: f16) callconv(.c) f16 { +fn __log10h(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log10_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log10_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(log10f(a)); + return @floatCast(log10_f32(a)); } -pub fn log10f(x_: f32) callconv(.c) f32 { +fn log10f(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log10_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log10_f32(x_: f32) f32 { const ivln10hi: f32 = 4.3432617188e-01; const ivln10lo: f32 = -3.1689971365e-05; const log10_2hi: f32 = 3.0102920532e-01; @@ -90,7 +93,10 @@ pub fn log10f(x_: f32) callconv(.c) f32 { return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; } -pub fn log10(x_: f64) callconv(.c) f64 { +fn log10(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log10_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log10_f64(x_: f64) f64 { const ivln10hi: f64 = 4.34294481878168880939e-01; const ivln10lo: f64 = 2.50829467116452752298e-11; const log10_2hi: f64 = 3.01029995663611771306e-01; @@ -165,11 +171,17 @@ pub fn log10(x_: f64) callconv(.c) f64 { return val_lo + val_hi; } -pub fn __log10x(a: f80) callconv(.c) f80 { +fn __log10x(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log10_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log10_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(log10q(a)); + return @floatCast(log10_f128(a)); } +fn log10q(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log10_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -182,7 +194,7 @@ pub fn __log10x(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.96%, worst case <= 0.565 ulp -pub fn log10q(x: f128) callconv(.c) f128 { +pub fn log10_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -359,124 +371,124 @@ pub fn log10q(x: f128) callconv(.c) f128 { pub fn log10l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log10(x), - 80 => return __log10x(x), - 128 => return log10q(x), - else => @compileError("unreachable"), + 64 => return log10_f64(x), + 80 => return log10_f80(x), + 128 => return log10_f128(x), + else => comptime unreachable, } } test "log10f() special" { - try expectEqual(log10f(0.0), -math.inf(f32)); - try expectEqual(log10f(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(log10f(1.0))); - try expectEqual(log10f(10.0), 1.0); - try expectEqual(log10f(0.1), -1.0); - try expectEqual(log10f(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(log10f(-1.0))); - try expect(math.isNan(log10f(-math.inf(f32)))); - try expect(math.isNan(log10f(math.nan(f32)))); - try expect(math.isNan(log10f(math.snan(f32)))); + try expectEqual(log10_f32(0.0), -math.inf(f32)); + try expectEqual(log10_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log10_f32(1.0))); + try expectEqual(log10_f32(10.0), 1.0); + try expectEqual(log10_f32(0.1), -1.0); + try expectEqual(log10_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log10_f32(-1.0))); + try expect(math.isNan(log10_f32(-math.inf(f32)))); + try expect(math.isNan(log10_f32(math.nan(f32)))); + try expect(math.isNan(log10_f32(math.snan(f32)))); } test "log10f() sanity" { - try expect(math.isNan(log10f(-0x1.0223a0p+3))); - try expectEqual(log10f(0x1.161868p+2), 0x1.46a9bcp-1); - try expect(math.isNan(log10f(-0x1.0c34b4p+3))); - try expect(math.isNan(log10f(-0x1.a206f0p+2))); - try expectEqual(log10f(0x1.288bbcp+3), 0x1.ef1300p-1); - try expectEqual(log10f(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit - try expect(math.isNan(log10f(-0x1.a05cc8p-2))); - try expectEqual(log10f(0x1.1f9efap-1), -0x1.0075ccp-2); - try expectEqual(log10f(0x1.8c5db0p-1), -0x1.c75df8p-4); - try expect(math.isNan(log10f(-0x1.5b86eap-1))); + try expect(math.isNan(log10_f32(-0x1.0223a0p+3))); + try expectEqual(log10_f32(0x1.161868p+2), 0x1.46a9bcp-1); + try expect(math.isNan(log10_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log10_f32(-0x1.a206f0p+2))); + try expectEqual(log10_f32(0x1.288bbcp+3), 0x1.ef1300p-1); + try expectEqual(log10_f32(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit + try expect(math.isNan(log10_f32(-0x1.a05cc8p-2))); + try expectEqual(log10_f32(0x1.1f9efap-1), -0x1.0075ccp-2); + try expectEqual(log10_f32(0x1.8c5db0p-1), -0x1.c75df8p-4); + try expect(math.isNan(log10_f32(-0x1.5b86eap-1))); } test "log10f() boundary" { - try expectEqual(log10f(0x1.fffffep+127), 0x1.344136p+5); // Max input value - try expectEqual(log10f(0x1p-149), -0x1.66d3e8p+5); // Min positive input value - try expect(math.isNan(log10f(-0x1p-149))); // Min negative input value - try expectEqual(log10f(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0 - try expectEqual(log10f(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0 - try expectEqual(log10f(0x1p-126), -0x1.2f7030p+5); // First subnormal - try expect(math.isNan(log10f(-0x1p-126))); // First negative subnormal + try expectEqual(log10_f32(0x1.fffffep+127), 0x1.344136p+5); // Max input value + try expectEqual(log10_f32(0x1p-149), -0x1.66d3e8p+5); // Min positive input value + try expect(math.isNan(log10_f32(-0x1p-149))); // Min negative input value + try expectEqual(log10_f32(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0 + try expectEqual(log10_f32(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0 + try expectEqual(log10_f32(0x1p-126), -0x1.2f7030p+5); // First subnormal + try expect(math.isNan(log10_f32(-0x1p-126))); // First negative subnormal } test "log10() special" { - try expectEqual(log10(0.0), -math.inf(f64)); - try expectEqual(log10(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log10(1.0))); - try expectEqual(log10(10.0), 1.0); - try expectEqual(log10(0.1), -1.0); - try expectEqual(log10(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log10(-1.0))); - try expect(math.isNan(log10(-math.inf(f64)))); - try expect(math.isNan(log10(math.nan(f64)))); - try expect(math.isNan(log10(math.snan(f64)))); + try expectEqual(log10_f64(0.0), -math.inf(f64)); + try expectEqual(log10_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log10_f64(1.0))); + try expectEqual(log10_f64(10.0), 1.0); + try expectEqual(log10_f64(0.1), -1.0); + try expectEqual(log10_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log10_f64(-1.0))); + try expect(math.isNan(log10_f64(-math.inf(f64)))); + try expect(math.isNan(log10_f64(math.nan(f64)))); + try expect(math.isNan(log10_f64(math.snan(f64)))); } test "log10() sanity" { - try expect(math.isNan(log10(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log10(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1); - try expect(math.isNan(log10(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log10(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log10(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1); - try expectEqual(log10(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3); - try expect(math.isNan(log10(-0x1.a05cc754481d1p-2))); - try expectEqual(log10(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2); - try expectEqual(log10(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4); - try expect(math.isNan(log10(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log10_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log10_f64(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1); + try expect(math.isNan(log10_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log10_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log10_f64(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1); + try expectEqual(log10_f64(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3); + try expect(math.isNan(log10_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log10_f64(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2); + try expectEqual(log10_f64(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4); + try expect(math.isNan(log10_f64(-0x1.5b86ea8118a0ep-1))); } test "log10() boundary" { - try expectEqual(log10(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value - try expectEqual(log10(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value - try expect(math.isNan(log10(-0x1p-1074))); // Min negative input value - try expectEqual(log10(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0 - try expectEqual(log10(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0 - try expectEqual(log10(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal - try expect(math.isNan(log10(-0x1p-1022))); // First negative subnormal + try expectEqual(log10_f64(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value + try expectEqual(log10_f64(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value + try expect(math.isNan(log10_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log10_f64(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0 + try expectEqual(log10_f64(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0 + try expectEqual(log10_f64(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal + try expect(math.isNan(log10_f64(-0x1p-1022))); // First negative subnormal } test "log10q() special" { - try expectEqual(log10q(0.0), -math.inf(f128)); - try expectEqual(log10q(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(log10q(1.0))); - try expectEqual(log10q(10.0), 1.0); - try expectEqual(log10q(0.1), -1.0); - try expectEqual(log10q(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(log10q(-1.0))); - try expect(math.isNan(log10q(-math.inf(f128)))); - try expect(math.isNan(log10q(math.nan(f128)))); - try expect(math.isNan(log10q(math.snan(f128)))); + try expectEqual(log10_f128(0.0), -math.inf(f128)); + try expectEqual(log10_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log10_f128(1.0))); + try expectEqual(log10_f128(10.0), 1.0); + try expectEqual(log10_f128(0.1), -1.0); + try expectEqual(log10_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log10_f128(-1.0))); + try expect(math.isNan(log10_f128(-math.inf(f128)))); + try expect(math.isNan(log10_f128(math.nan(f128)))); + try expect(math.isNan(log10_f128(math.snan(f128)))); } test "log10q() sanity" { - try expectEqual(log10q(2.1744503117482705706605762784484114e1949), 1.949337349488073972035715318447419e3); - try expectEqual(log10q(2.3695331993665660983204066767386505e2150), 2.1503746627979481420243846411400265e3); - try expectEqual(log10q(1.8071775728314983136779370752110857e612), 6.122570008283284411311428111991705e2); - try expectEqual(log10q(2.612170297226630737309271722008693e-2629), -2.628582998513179919647069989114319e3); - try expectEqual(log10q(8.485091636263895897993044621224502e-3748), -3.7470713434630800881474518447042895e3); - try expectEqual(log10q(4.3668077579803801413736022136116655e-4051), -4.0503598359268068567757367259544416e3); - try expectEqual(log10q(2.9321353260885285826237030859036923e4830), 4.830467184010313310864606285356782e3); - try expectEqual(log10q(6.6119754254652455408442826553161645e-1417), -1.416179668769227128601620567685071e3); - try expectEqual(log10q(5.2459104673488555418645321788108695e4178), 4.178719820874155944446586083585479e3); - try expectEqual(log10q(7.809812890804996586377267218360886e-418), -4.1710735937091966815220294599598215e2); + try expectEqual(log10_f128(2.1744503117482705706605762784484114e1949), 1.949337349488073972035715318447419e3); + try expectEqual(log10_f128(2.3695331993665660983204066767386505e2150), 2.1503746627979481420243846411400265e3); + try expectEqual(log10_f128(1.8071775728314983136779370752110857e612), 6.122570008283284411311428111991705e2); + try expectEqual(log10_f128(2.612170297226630737309271722008693e-2629), -2.628582998513179919647069989114319e3); + try expectEqual(log10_f128(8.485091636263895897993044621224502e-3748), -3.7470713434630800881474518447042895e3); + try expectEqual(log10_f128(4.3668077579803801413736022136116655e-4051), -4.0503598359268068567757367259544416e3); + try expectEqual(log10_f128(2.9321353260885285826237030859036923e4830), 4.830467184010313310864606285356782e3); + try expectEqual(log10_f128(6.6119754254652455408442826553161645e-1417), -1.416179668769227128601620567685071e3); + try expectEqual(log10_f128(5.2459104673488555418645321788108695e4178), 4.178719820874155944446586083585479e3); + try expectEqual(log10_f128(7.809812890804996586377267218360886e-418), -4.1710735937091966815220294599598215e2); // testing near 1 - try expectEqual(log10q(1.0291437165967803055610652052109798e0), 1.2476026819466393459130418401605807e-2); - try expectEqual(log10q(1.043095786320424537962914257605007e0), 1.8324191034706598279642145362763252e-2); - try expectEqual(log10q(9.900264873754467234601150948947179e-1), -4.3531860417287584780652055666513634e-3); - try expectEqual(log10q(1.038295346547007736348611217636062e0), 1.6320907588397540309035279023485962e-2); - try expectEqual(log10q(9.821701941230028324703038578036285e-1), -7.813249520562034832371814409278784e-3); - try expectEqual(log10q(9.593555263530179895381522214847791e-1), -1.8020418356217558657107271163588764e-2); + try expectEqual(log10_f128(1.0291437165967803055610652052109798e0), 1.2476026819466393459130418401605807e-2); + try expectEqual(log10_f128(1.043095786320424537962914257605007e0), 1.8324191034706598279642145362763252e-2); + try expectEqual(log10_f128(9.900264873754467234601150948947179e-1), -4.3531860417287584780652055666513634e-3); + try expectEqual(log10_f128(1.038295346547007736348611217636062e0), 1.6320907588397540309035279023485962e-2); + try expectEqual(log10_f128(9.821701941230028324703038578036285e-1), -7.813249520562034832371814409278784e-3); + try expectEqual(log10_f128(9.593555263530179895381522214847791e-1), -1.8020418356217558657107271163588764e-2); } test "log10q() boundary" { - try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp16383), 0x1.34413509f79fef311f12b35816f9p12); // Max input value - try expectEqual(log10q(0x1p-16494), -0x1.3653051d20c18a143b801b7c5661p12); // Min positive input value - try expect(math.isNan(log10q(-0x1p-16494))); // Min negative input value - try expectEqual(log10q(0x1.0000000000000000000000000001p0), 0x1.bcb7b1526e50e32a6ab7555f5a67p-114); // Last value before result reaches +0 - try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.bcb7b1526e50e32a6ab7555f5a68p-115); // Last value before result reaches -0 - try expectEqual(log10q(0x1p-16382), -0x1.343793004f503231a589bac27c38p12); // First subnormal - try expect(math.isNan(log10q(-0x1p-16382))); // First negative subnormal + try expectEqual(log10_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1.34413509f79fef311f12b35816f9p12); // Max input value + try expectEqual(log10_f128(0x1p-16494), -0x1.3653051d20c18a143b801b7c5661p12); // Min positive input value + try expect(math.isNan(log10_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log10_f128(0x1.0000000000000000000000000001p0), 0x1.bcb7b1526e50e32a6ab7555f5a67p-114); // Last value before result reaches +0 + try expectEqual(log10_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1.bcb7b1526e50e32a6ab7555f5a68p-115); // Last value before result reaches -0 + try expectEqual(log10_f128(0x1p-16382), -0x1.343793004f503231a589bac27c38p12); // First subnormal + try expect(math.isNan(log10_f128(-0x1p-16382))); // First negative subnormal } diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig index 8db17aaf3f26f257482af43b7bc125d4747dbfe2..0806fb079419787d33dd3b825b4057aac51f1397 100644 --- a/lib/compiler_rt/log2.zig +++ b/lib/compiler_rt/log2.zig @@ -19,19 +19,22 @@ comptime { symbol(&log2f, "log2f"); symbol(&log2, "log2"); symbol(&__log2x, "__log2x"); - if (compiler_rt.want_ppc_abi) { - symbol(&log2q, "log2f128"); - } - symbol(&log2q, "log2q"); + symbol(&log2q, "log2f128"); symbol(&log2l, "log2l"); } -pub fn __log2h(a: f16) callconv(.c) f16 { +fn __log2h(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log2_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log2_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(log2f(a)); + return @floatCast(log2_f32(a)); } -pub fn log2f(x_: f32) callconv(.c) f32 { +fn log2f(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log2_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log2_f32(x_: f32) f32 { const ivln2hi: f32 = 1.4428710938e+00; const ivln2lo: f32 = -1.7605285393e-04; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -87,7 +90,10 @@ pub fn log2f(x_: f32) callconv(.c) f32 { return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @as(f32, @floatFromInt(k)); } -pub fn log2(x_: f64) callconv(.c) f64 { +fn log2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log2_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log2_f64(x_: f64) f64 { const ivln2hi: f64 = 1.44269504072144627571e+00; const ivln2lo: f64 = 1.67517131648865118353e-10; const Lg1: f64 = 6.666666666666735130e-01; @@ -158,11 +164,17 @@ pub fn log2(x_: f64) callconv(.c) f64 { return val_lo + val_hi; } -pub fn __log2x(a: f80) callconv(.c) f80 { +fn __log2x(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log2_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log2_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(log2q(a)); + return @floatCast(log2_f128(a)); } +fn log2q(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log2_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -175,7 +187,7 @@ pub fn __log2x(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.86%, worst case <= 0.546 ulp -pub fn log2q(x: f128) callconv(.c) f128 { +pub fn log2_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -351,117 +363,117 @@ pub fn log2q(x: f128) callconv(.c) f128 { pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log2(x), - 80 => return __log2x(x), - 128 => return log2q(x), - else => @compileError("unreachable"), + 64 => return log2_f64(x), + 80 => return log2_f80(x), + 128 => return log2_f128(x), + else => comptime unreachable, } } test "log2f() special" { - try expectEqual(log2f(0.0), -math.inf(f32)); - try expectEqual(log2f(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(log2f(1.0))); - try expectEqual(log2f(2.0), 1.0); - try expectEqual(log2f(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(log2f(-1.0))); - try expect(math.isNan(log2f(-math.inf(f32)))); - try expect(math.isNan(log2f(math.nan(f32)))); - try expect(math.isNan(log2f(math.snan(f32)))); + try expectEqual(log2_f32(0.0), -math.inf(f32)); + try expectEqual(log2_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log2_f32(1.0))); + try expectEqual(log2_f32(2.0), 1.0); + try expectEqual(log2_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log2_f32(-1.0))); + try expect(math.isNan(log2_f32(-math.inf(f32)))); + try expect(math.isNan(log2_f32(math.nan(f32)))); + try expect(math.isNan(log2_f32(math.snan(f32)))); } test "log2f() sanity" { - try expect(math.isNan(log2f(-0x1.0223a0p+3))); - try expectEqual(log2f(0x1.161868p+2), 0x1.0f49acp+1); - try expect(math.isNan(log2f(-0x1.0c34b4p+3))); - try expect(math.isNan(log2f(-0x1.a206f0p+2))); - try expectEqual(log2f(0x1.288bbcp+3), 0x1.9b2676p+1); - try expectEqual(log2f(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit - try expect(math.isNan(log2f(-0x1.a05cc8p-2))); - try expectEqual(log2f(0x1.1f9efap-1), -0x1.a9f89ap-1); - try expectEqual(log2f(0x1.8c5db0p-1), -0x1.7a2c96p-2); - try expect(math.isNan(log2f(-0x1.5b86eap-1))); + try expect(math.isNan(log2_f32(-0x1.0223a0p+3))); + try expectEqual(log2_f32(0x1.161868p+2), 0x1.0f49acp+1); + try expect(math.isNan(log2_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log2_f32(-0x1.a206f0p+2))); + try expectEqual(log2_f32(0x1.288bbcp+3), 0x1.9b2676p+1); + try expectEqual(log2_f32(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit + try expect(math.isNan(log2_f32(-0x1.a05cc8p-2))); + try expectEqual(log2_f32(0x1.1f9efap-1), -0x1.a9f89ap-1); + try expectEqual(log2_f32(0x1.8c5db0p-1), -0x1.7a2c96p-2); + try expect(math.isNan(log2_f32(-0x1.5b86eap-1))); } test "log2f() boundary" { - try expectEqual(log2f(0x1.fffffep+127), 0x1p+7); // Max input value - try expectEqual(log2f(0x1p-149), -0x1.2ap+7); // Min positive input value - try expect(math.isNan(log2f(-0x1p-149))); // Min negative input value - try expectEqual(log2f(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0 - try expectEqual(log2f(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0 - try expectEqual(log2f(0x1p-126), -0x1.f8p+6); // First subnormal - try expect(math.isNan(log2f(-0x1p-126))); // First negative subnormal + try expectEqual(log2_f32(0x1.fffffep+127), 0x1p+7); // Max input value + try expectEqual(log2_f32(0x1p-149), -0x1.2ap+7); // Min positive input value + try expect(math.isNan(log2_f32(-0x1p-149))); // Min negative input value + try expectEqual(log2_f32(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0 + try expectEqual(log2_f32(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0 + try expectEqual(log2_f32(0x1p-126), -0x1.f8p+6); // First subnormal + try expect(math.isNan(log2_f32(-0x1p-126))); // First negative subnormal } test "log2() special" { - try expectEqual(log2(0.0), -math.inf(f64)); - try expectEqual(log2(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log2(1.0))); - try expectEqual(log2(2.0), 1.0); - try expectEqual(log2(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log2(-1.0))); - try expect(math.isNan(log2(-math.inf(f64)))); - try expect(math.isNan(log2(math.nan(f64)))); - try expect(math.isNan(log2(math.snan(f64)))); + try expectEqual(log2_f64(0.0), -math.inf(f64)); + try expectEqual(log2_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log2_f64(1.0))); + try expectEqual(log2_f64(2.0), 1.0); + try expectEqual(log2_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log2_f64(-1.0))); + try expect(math.isNan(log2_f64(-math.inf(f64)))); + try expect(math.isNan(log2_f64(math.nan(f64)))); + try expect(math.isNan(log2_f64(math.snan(f64)))); } test "log2() sanity" { - try expect(math.isNan(log2(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log2(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1); - try expect(math.isNan(log2(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log2(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log2(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1); - try expectEqual(log2(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1); - try expect(math.isNan(log2(-0x1.a05cc754481d1p-2))); - try expectEqual(log2(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1); - try expectEqual(log2(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2); - try expect(math.isNan(log2(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log2_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log2_f64(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1); + try expect(math.isNan(log2_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log2_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log2_f64(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1); + try expectEqual(log2_f64(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1); + try expect(math.isNan(log2_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log2_f64(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1); + try expectEqual(log2_f64(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2); + try expect(math.isNan(log2_f64(-0x1.5b86ea8118a0ep-1))); } test "log2() boundary" { - try expectEqual(log2(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value - try expectEqual(log2(0x1p-1074), -0x1.0c8p+10); // Min positive input value - try expect(math.isNan(log2(-0x1p-1074))); // Min negative input value - try expectEqual(log2(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0 - try expectEqual(log2(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0 - try expectEqual(log2(0x1p-1022), -0x1.ffp+9); // First subnormal - try expect(math.isNan(log2(-0x1p-1022))); // First negative subnormal + try expectEqual(log2_f64(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value + try expectEqual(log2_f64(0x1p-1074), -0x1.0c8p+10); // Min positive input value + try expect(math.isNan(log2_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log2_f64(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0 + try expectEqual(log2_f64(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0 + try expectEqual(log2_f64(0x1p-1022), -0x1.ffp+9); // First subnormal + try expect(math.isNan(log2_f64(-0x1p-1022))); // First negative subnormal } test "log2q() special" { - try expectEqual(log2q(0.0), -math.inf(f128)); - try expectEqual(log2q(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(log2q(1.0))); - try expectEqual(log2q(2.0), 1.0); - try expectEqual(log2q(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(log2q(-1.0))); - try expect(math.isNan(log2q(-math.inf(f128)))); - try expect(math.isNan(log2q(math.nan(f128)))); - try expect(math.isNan(log2q(math.snan(f128)))); + try expectEqual(log2_f128(0.0), -math.inf(f128)); + try expectEqual(log2_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log2_f128(1.0))); + try expectEqual(log2_f128(2.0), 1.0); + try expectEqual(log2_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log2_f128(-1.0))); + try expect(math.isNan(log2_f128(-math.inf(f128)))); + try expect(math.isNan(log2_f128(math.nan(f128)))); + try expect(math.isNan(log2_f128(math.snan(f128)))); } test "log2q() boundary" { - try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value - try expectEqual(log2q(0x1p-16494), -0x1.01b8p14); // Min positive input value - try expect(math.isNan(log2q(-0x1p-16494))); // Min negative input value - try expectEqual(log2q(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0 - try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0 - try expectEqual(log2q(0x1p-16382), -0x1.fffp13); // First subnormal - try expect(math.isNan(log2q(-0x1p-16382))); // First negative subnormal + try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value + try expectEqual(log2_f128(0x1p-16494), -0x1.01b8p14); // Min positive input value + try expect(math.isNan(log2_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log2_f128(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0 + try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0 + try expectEqual(log2_f128(0x1p-16382), -0x1.fffp13); // First subnormal + try expect(math.isNan(log2_f128(-0x1p-16382))); // First negative subnormal } test "log2q() sanity" { - try expectEqual(log2q(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1); - try expectEqual(log2q(8.346531942223744e15), 5.28900982928636641107356163006646e1); - try expectEqual(log2q(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1); - try expectEqual(log2q(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1); - try expectEqual(log2q(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1); - try expectEqual(log2q(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1); + try expectEqual(log2_f128(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1); + try expectEqual(log2_f128(8.346531942223744e15), 5.28900982928636641107356163006646e1); + try expectEqual(log2_f128(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1); + try expectEqual(log2_f128(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1); + try expectEqual(log2_f128(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1); + try expectEqual(log2_f128(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1); // test near 1 - try expectEqual(log2q(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2); - try expectEqual(log2q(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4); - try expectEqual(log2q(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2); - try expectEqual(log2q(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2); - try expectEqual(log2q(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2); + try expectEqual(log2_f128(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2); + try expectEqual(log2_f128(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4); + try expectEqual(log2_f128(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2); + try expectEqual(log2_f128(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2); + try expectEqual(log2_f128(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2); } diff --git a/lib/compiler_rt/mulc3.zig b/lib/compiler_rt/mulc3.zig index eea753245f7687b2e3e9b65c12bdd278f1a3c757..fc0f2d24b4f603d9c933eb1328dbf5b73e4f41bc 100644 --- a/lib/compiler_rt/mulc3.zig +++ b/lib/compiler_rt/mulc3.zig @@ -3,19 +3,80 @@ const isNan = std.math.isNan; const isInf = std.math.isInf; const copysign = std.math.copysign; -pub fn Complex(comptime T: type) type { - return extern struct { - real: T, - imag: T, - }; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const Complex = compiler_rt.Complex; + +comptime { + if (@import("builtin").zig_backend != .stage2_c) { + symbol(&__mulhc3, "__mulhc3"); + symbol(&__mulsc3, "__mulsc3"); + symbol(&__muldc3, "__muldc3"); + symbol(&__mulxc3, "__mulxc3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__multc3, "__mulkc3"); + } else { + symbol(&__multc3, "__multc3"); + } + } +} + +fn __mulhc3(lhs_real: compiler_rt.f16.Abi, lhs_imag: compiler_rt.f16.Abi, rhs_real: compiler_rt.f16.Abi, rhs_imag: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.complex.Abi { + return compiler_rt.f16.complex.toAbi(mul_cf16( + compiler_rt.f16.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f16.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf16(a: Complex(f16), b: Complex(f16)) Complex(f16) { + return mulc3(f16, a, b); +} + +fn __mulsc3(lhs_real: compiler_rt.f32.Abi, lhs_imag: compiler_rt.f32.Abi, rhs_real: compiler_rt.f32.Abi, rhs_imag: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.complex.Abi { + return compiler_rt.f32.complex.toAbi(mul_cf32( + compiler_rt.f32.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f32.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf32(a: Complex(f32), b: Complex(f32)) Complex(f32) { + return mulc3(f32, a, b); +} + +fn __muldc3(lhs_real: compiler_rt.f64.Abi, lhs_imag: compiler_rt.f64.Abi, rhs_real: compiler_rt.f64.Abi, rhs_imag: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.complex.Abi { + return compiler_rt.f64.complex.toAbi(mul_cf64( + compiler_rt.f64.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f64.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf64(a: Complex(f64), b: Complex(f64)) Complex(f64) { + return mulc3(f64, a, b); +} + +fn __mulxc3(lhs_real: compiler_rt.f80.Abi, lhs_imag: compiler_rt.f80.Abi, rhs_real: compiler_rt.f80.Abi, rhs_imag: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.complex.Abi { + return compiler_rt.f80.complex.toAbi(mul_cf80( + compiler_rt.f80.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f80.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf80(a: Complex(f80), b: Complex(f80)) Complex(f80) { + return mulc3(f80, a, b); +} + +fn __multc3(lhs_real: compiler_rt.f128.Abi, lhs_imag: compiler_rt.f128.Abi, rhs_real: compiler_rt.f128.Abi, rhs_imag: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.complex.Abi { + return compiler_rt.f128.complex.toAbi(mul_cf128( + compiler_rt.f128.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f128.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf128(a: Complex(f128), b: Complex(f128)) Complex(f128) { + return mulc3(f128, a, b); } /// Implementation based on Annex G of C17 Standard (N2176) -pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Complex(T) { - var a = a_in; - var b = b_in; - var c = c_in; - var d = d_in; +inline fn mulc3(comptime T: type, lhs: Complex(T), rhs: Complex(T)) Complex(T) { + var a = lhs.real; + var b = lhs.imag; + var c = rhs.real; + var d = rhs.imag; const ac = a * c; const bd = b * d; @@ -77,3 +138,7 @@ pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Comple } return z; } + +test { + _ = @import("mulc3_test.zig"); +} diff --git a/lib/compiler_rt/mulc3_test.zig b/lib/compiler_rt/mulc3_test.zig index 3872cb34a6f9198dce4b482be03de720dce17696..748a3bc120ad6cfa3f82b2226f537a6bc63771b6 100644 --- a/lib/compiler_rt/mulc3_test.zig +++ b/lib/compiler_rt/mulc3_test.zig @@ -2,64 +2,45 @@ const std = @import("std"); const math = std.math; const expect = std.testing.expect; -const Complex = @import("./mulc3.zig").Complex; -const __mulhc3 = @import("./mulhc3.zig").__mulhc3; -const __mulsc3 = @import("./mulsc3.zig").__mulsc3; -const __muldc3 = @import("./muldc3.zig").__muldc3; -const __mulxc3 = @import("./mulxc3.zig").__mulxc3; -const __multc3 = @import("./multc3.zig").__multc3; +const Complex = @import("../compiler_rt.zig").Complex; +const impl = @import("mulc3.zig"); +const mul_cf16 = impl.mul_cf16; +const mul_cf32 = impl.mul_cf32; +const mul_cf64 = impl.mul_cf64; +const mul_cf80 = impl.mul_cf80; +const mul_cf128 = impl.mul_cf128; test "mulc3" { - try testMul(f16, __mulhc3); - try testMul(f32, __mulsc3); - try testMul(f64, __muldc3); - try testMul(f80, __mulxc3); - try testMul(f128, __multc3); + try testMul(f16, mul_cf16); + try testMul(f32, mul_cf32); + try testMul(f64, mul_cf64); + try testMul(f80, mul_cf80); + try testMul(f128, mul_cf128); } -fn testMul(comptime T: type, comptime f: fn (T, T, T, T) callconv(.c) Complex(T)) !void { +fn testMul(comptime T: type, comptime f: fn (Complex(T), Complex(T)) Complex(T)) !void { { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -1.0, .imag = 0.0 }); try expect(result.real == -1.0); - try expect(result.imag == 0.0); + try expect(math.isPositiveZero(result.imag)); } { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -4.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -4.0, .imag = 0.0 }); try expect(result.real == -4.0); - try expect(result.imag == 0.0); + try expect(math.isPositiveZero(result.imag)); } { // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, // then the result of the * operator is an infinity; - const a: T = math.inf(T); - const b: T = -math.inf(T); - const c: T = 1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == -math.inf(T)); + const result = f(.{ .real = math.inf(T), .imag = -math.inf(T) }, .{ .real = 1.0, .imag = 0.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isNegativeInf(result.imag)); } { // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, // then the result of the * operator is an infinity; - const a: T = math.inf(T); - const b: T = -1.0; - const c: T = 1.0; - const d: T = math.inf(T); - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + const result = f(.{ .real = math.inf(T), .imag = -1.0 }, .{ .real = 1.0, .imag = math.inf(T) }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } } diff --git a/lib/compiler_rt/muldc3.zig b/lib/compiler_rt/muldc3.zig deleted file mode 100644 index d5facaa2b645670b6bf6e0953ec6b73342342329..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/muldc3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const mulc3 = @import("./mulc3.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__muldc3, "__muldc3"); - } -} - -pub fn __muldc3(a: f64, b: f64, c: f64, d: f64) callconv(.c) mulc3.Complex(f64) { - return mulc3.mulc3(f64, a, b, c, d); -} diff --git a/lib/compiler_rt/muldf3.zig b/lib/compiler_rt/muldf3.zig deleted file mode 100644 index b8809e76da8d11e04c181d9dea86911aaac1cb29..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/muldf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dmul, "__aeabi_dmul"); - } else { - symbol(&__muldf3, "__muldf3"); - } -} - -pub fn __muldf3(a: f64, b: f64) callconv(.c) f64 { - return mulf3(f64, a, b); -} - -fn __aeabi_dmul(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return mulf3(f64, a, b); -} diff --git a/lib/compiler_rt/mulf3.zig b/lib/compiler_rt/mulf3.zig index d6b5a4719068cf2e27345f73e5f29994fc72e6d3..7367339dbc82f74dc99a9f6de7f842e8cbb71968 100644 --- a/lib/compiler_rt/mulf3.zig +++ b/lib/compiler_rt/mulf3.zig @@ -2,10 +2,76 @@ const std = @import("std"); const math = std.math; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + symbol(&__mulhf3, "__mulhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fmul, "__aeabi_fmul"); + symbol(&__aeabi_dmul, "__aeabi_dmul"); + } else { + symbol(&__mulsf3, "__mulsf3"); + symbol(&__muldf3, "__muldf3"); + } + symbol(&__mulxf3, "__mulxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__multf3, "__mulkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_mul, "_Qp_mul"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__multf3, "_Q_mul"); + } else { + symbol(&__multf3, "__multf3"); + } +} + +fn __mulhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(mul_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn mul_f16(a: f16, b: f16) f16 { + return mulf3(f16, a, b); +} + +fn __mulsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(mul_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fmul(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return mul_f32(a, b); +} +pub fn mul_f32(a: f32, b: f32) f32 { + return mulf3(f32, a, b); +} + +fn __muldf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(mul_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dmul(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return mul_f64(a, b); +} +pub fn mul_f64(a: f64, b: f64) f64 { + return mulf3(f64, a, b); +} + +fn __mulxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(mul_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn mul_f80(a: f80, b: f80) f80 { + return mulf3(f80, a, b); +} + +fn __multf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(mul_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_mul(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { + c.* = mul_f128(a.*, b.*); +} +pub fn mul_f128(a: f128, b: f128) f128 { + return mulf3(f128, a, b); +} /// Ported from: /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc -pub inline fn mulf3(comptime T: type, a: T, b: T) T { +inline fn mulf3(comptime T: type, a: T, b: T) T { @setRuntimeSafety(compiler_rt.test_safety); const typeWidth = @typeInfo(T).float.bits; const significandBits = math.floatMantissaBits(T); diff --git a/lib/compiler_rt/mulf3_test.zig b/lib/compiler_rt/mulf3_test.zig index 751b8933f65bc20e4b630c125fa60f42d5e27529..a2595e21a6d1ca5dd44f1ce67e6dfb6b4ee4cd9f 100644 --- a/lib/compiler_rt/mulf3_test.zig +++ b/lib/compiler_rt/mulf3_test.zig @@ -7,10 +7,12 @@ const math = std.math; const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64); const inf128: f128 = @bitCast(@as(u128, 0x7fff000000000000) << 64); -const __multf3 = @import("multf3.zig").__multf3; -const __mulxf3 = @import("mulxf3.zig").__mulxf3; -const __muldf3 = @import("muldf3.zig").__muldf3; -const __mulsf3 = @import("mulsf3.zig").__mulsf3; +const impl = @import("mulf3.zig"); +const mul_f16 = impl.mul_f16; +const mul_f32 = impl.mul_f32; +const mul_f64 = impl.mul_f64; +const mul_f80 = impl.mul_f80; +const mul_f128 = impl.mul_f128; // return true if equal // use two 64-bit integers instead of one 128-bit integer @@ -34,8 +36,8 @@ fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { return false; } -fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __multf3(a, b); +fn test_mul_f128(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = mul_f128(a, b); if (compareResultLD(x, expected_hi, expected_lo)) return; @@ -49,68 +51,68 @@ fn makeNaN128(rand: u64) f128 { } test "multf3" { // qNaN * any = qNaN - try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + try test_mul_f128(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); // NaN * any = NaN const a = makeNaN128(0x800030000000); - try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + try test_mul_f128(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); // inf * any = inf - try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + try test_mul_f128(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); // any * any - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x40042eab345678439abcdefea5678234))), @as(f128, @bitCast(@as(u128, 0x3ffeedcb34a235253948765432134675))), 0x400423e7f9e3c9fc, 0xd906c2c2a85777c4, ); - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50))), @as(f128, @bitCast(@as(u128, 0x3ff6ed8764648369535adf4be3214568))), 0x3fc52a163c6223fc, 0xc94c4bf0430768b4, ); - try test__multf3( + try test_mul_f128( 0x1.234425696abcad34a35eeffefdcbap+456, 0x451.ed98d76e5d46e5f24323dff21ffp+600, 0x44293a91de5e0e94, 0xe8ed17cc2cdf64ac, ); - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x3f154356473c82a9fabf2d22ace345df))), @as(f128, @bitCast(@as(u128, 0x3e38eda98765476743ab21da23d45679))), 0x3d4f37c1a3137cae, 0xfc6807048bc2836a, ); - try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); + try test_mul_f128(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); // Denormal operands. - try test__multf3( + try test_mul_f128( 0x0.0000000000000000000000000001p-16382, 0x1p16383, 0x3f90000000000000, 0x0, ); - try test__multf3( + try test_mul_f128( 0x1p16383, 0x0.0000000000000000000000000001p-16382, 0x3f90000000000000, 0x0, ); - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); - try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); + try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); + try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); + try test_mul_f128(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); } const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))); -fn test__mulxf3(a: f80, b: f80, expected: u80) !void { - const x = __mulxf3(a, b); +fn test_mul_f80(a: f80, b: f80, expected: u80) !void { + const x = mul_f80(a, b); const rep: u80 = @bitCast(x); if (rep == expected) @@ -124,47 +126,47 @@ fn test__mulxf3(a: f80, b: f80, expected: u80) !void { test "mulxf3" { // NaN * any = NaN - try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); - try test__mulxf3(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); + try test_mul_f80(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); + try test_mul_f80(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); // any * NaN = NaN - try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80))); - try test__mulxf3(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80))); + try test_mul_f80(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80))); + try test_mul_f80(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80))); // NaN * inf = NaN - try test__mulxf3(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80))); + try test_mul_f80(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80))); // inf * NaN = NaN - try test__mulxf3(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80))); + try test_mul_f80(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80))); // inf * inf = inf - try test__mulxf3(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); // inf * -inf = -inf - try test__mulxf3(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); + try test_mul_f80(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); // -inf + inf = -inf - try test__mulxf3(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); + try test_mul_f80(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); // inf * any = inf - try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80)))); // any * inf = inf - try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); // any * any - try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); - try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact + try test_mul_f80(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); + try test_mul_f80(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up - try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal + try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even + try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up + try test_mul_f80(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal } diff --git a/lib/compiler_rt/mulhc3.zig b/lib/compiler_rt/mulhc3.zig deleted file mode 100644 index 4e0d3f875389ddf2f02bb7ddb3f75106e6d48513..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulhc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulhc3, "__mulhc3"); - } -} - -pub fn __mulhc3(a: f16, b: f16, c: f16, d: f16) callconv(.c) mulc3.Complex(f16) { - return mulc3.mulc3(f16, a, b, c, d); -} diff --git a/lib/compiler_rt/mulhf3.zig b/lib/compiler_rt/mulhf3.zig deleted file mode 100644 index 46ce7a6b999005704db84280e3e83c7be05985b6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - symbol(&__mulhf3, "__mulhf3"); -} - -pub fn __mulhf3(a: f16, b: f16) callconv(.c) f16 { - return mulf3(f16, a, b); -} diff --git a/lib/compiler_rt/mulsc3.zig b/lib/compiler_rt/mulsc3.zig deleted file mode 100644 index e735e65eade6a77f908abe8b4b25e8fc30af7f9f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulsc3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulsc3, "__mulsc3"); - } -} - -pub fn __mulsc3(a: f32, b: f32, c: f32, d: f32) callconv(.c) mulc3.Complex(f32) { - return mulc3.mulc3(f32, a, b, c, d); -} diff --git a/lib/compiler_rt/mulsf3.zig b/lib/compiler_rt/mulsf3.zig deleted file mode 100644 index 81f9eafae213d8cba10579b86f109bdfd361ba41..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulsf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fmul, "__aeabi_fmul"); - } else { - symbol(&__mulsf3, "__mulsf3"); - } -} - -pub fn __mulsf3(a: f32, b: f32) callconv(.c) f32 { - return mulf3(f32, a, b); -} - -fn __aeabi_fmul(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return mulf3(f32, a, b); -} diff --git a/lib/compiler_rt/multc3.zig b/lib/compiler_rt/multc3.zig deleted file mode 100644 index 4914735b10f63ec38d3487738e461769db6f8669..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/multc3.zig +++ /dev/null @@ -1,15 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - if (compiler_rt.want_ppc_abi) - symbol(&__multc3, "__mulkc3"); - symbol(&__multc3, "__multc3"); - } -} - -pub fn __multc3(a: f128, b: f128, c: f128, d: f128) callconv(.c) mulc3.Complex(f128) { - return mulc3.mulc3(f128, a, b, c, d); -} diff --git a/lib/compiler_rt/multf3.zig b/lib/compiler_rt/multf3.zig deleted file mode 100644 index 7d10c70777176e7a8580eb3b909546e42535785e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/multf3.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__multf3, "__mulkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_mul, "_Qp_mul"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__multf3, "_Q_mul"); - } - symbol(&__multf3, "__multf3"); -} - -pub fn __multf3(a: f128, b: f128) callconv(.c) f128 { - return mulf3(f128, a, b); -} - -fn _Qp_mul(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = mulf3(f128, a.*, b.*); -} diff --git a/lib/compiler_rt/mulvsi3.zig b/lib/compiler_rt/mulvsi3.zig index 0935ea497afa52a46f515c83c40c2d8cc5bc02db..f2456fa7cb825a36a359d667d26e5f06eb2c95e4 100644 --- a/lib/compiler_rt/mulvsi3.zig +++ b/lib/compiler_rt/mulvsi3.zig @@ -1,7 +1,8 @@ const testing = @import("std").testing; const mulv = @import("mulo.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__mulvsi3, "__mulvsi3"); @@ -10,7 +11,7 @@ comptime { pub fn __mulvsi3(a: i32, b: i32) callconv(.c) i32 { var overflow: c_int = 0; const sum = mulv.__mulosi4(a, b, &overflow); - if (overflow != 0) @panic("compiler-rt: integer overflow"); + if (overflow != 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/mulxc3.zig b/lib/compiler_rt/mulxc3.zig deleted file mode 100644 index ac0e189f63ba4d4ce2f0a753c4f7409e0b551d23..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulxc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulxc3, "__mulxc3"); - } -} - -pub fn __mulxc3(a: f80, b: f80, c: f80, d: f80) callconv(.c) mulc3.Complex(f80) { - return mulc3.mulc3(f80, a, b, c, d); -} diff --git a/lib/compiler_rt/mulxf3.zig b/lib/compiler_rt/mulxf3.zig deleted file mode 100644 index dcf783a4a6bc434275416e9da0079f65b3354277..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulxf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - symbol(&__mulxf3, "__mulxf3"); -} - -pub fn __mulxf3(a: f80, b: f80) callconv(.c) f80 { - return mulf3(f80, a, b); -} diff --git a/lib/compiler_rt/negv.zig b/lib/compiler_rt/negv.zig index 7c67a51c34ab72f9c3f0038024e45ca79413d955..c6d61611f1b24d3697dcdc4201f5ff2d8c1cf40c 100644 --- a/lib/compiler_rt/negv.zig +++ b/lib/compiler_rt/negv.zig @@ -33,8 +33,7 @@ inline fn negvXi(comptime ST: type, a: ST) ST { }; const N: UT = @bitSizeOf(ST); const min: ST = @as(ST, @bitCast((@as(UT, 1) << (N - 1)))); - if (a == min) - @panic("compiler_rt negv: overflow"); + if (a == min) @panic("integer overflow"); return -a; } diff --git a/lib/compiler_rt/os_version_check.zig b/lib/compiler_rt/os_version_check.zig index e575fef9ce553fee90cc9f7cc900689c5804cb20..96724a14e8092aae7693e4ab869ab3282a9ea762 100644 --- a/lib/compiler_rt/os_version_check.zig +++ b/lib/compiler_rt/os_version_check.zig @@ -3,7 +3,6 @@ const testing = std.testing; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; -const panic = @import("../compiler_rt.zig").panic; const have_availability_version_check = builtin.os.tag.isDarwin() and builtin.os.version_range.semver.min.order(.{ .major = 10, .minor = 15, .patch = 0 }).compare(.gte); diff --git a/lib/compiler_rt/parity.zig b/lib/compiler_rt/parity.zig index e3881699042fafc3fc0da7415e6fb2bb6d1aedde..9540cf49f629556b73f77067ddcf90944afdf21b 100644 --- a/lib/compiler_rt/parity.zig +++ b/lib/compiler_rt/parity.zig @@ -1,6 +1,7 @@ //! parity - if number of bits set is even => 0, else => 1 //! - pariytXi2_generic for big and little endian -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__paritysi2, "__paritysi2"); diff --git a/lib/compiler_rt/popcount.zig b/lib/compiler_rt/popcount.zig index b1ef500ea117514d08b598e4209770bd4b879b1f..3b9d867548f62d9ab7da321786cb737effa2646d 100644 --- a/lib/compiler_rt/popcount.zig +++ b/lib/compiler_rt/popcount.zig @@ -6,7 +6,8 @@ //! TAOCP: Combinational Algorithms, Bitwise Tricks And Techniques, //! subsubsection "Working with the rightmost bits" and "Sideways addition". -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__popcountsi2, "__popcountsi2"); diff --git a/lib/compiler_rt/powiXf2.zig b/lib/compiler_rt/powiXf2.zig index b2a1e3e6989ba85538243483d14fd92ad0e3158d..dd8b477f152144ce7206f4ce54caa77c1a4ead36 100644 --- a/lib/compiler_rt/powiXf2.zig +++ b/lib/compiler_rt/powiXf2.zig @@ -4,16 +4,18 @@ //! error propagation and this method is optimized for performance, not accuracy. const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__powihf2, "__powihf2"); symbol(&__powisf2, "__powisf2"); symbol(&__powidf2, "__powidf2"); - if (compiler_rt.want_ppc_abi) - symbol(&__powitf2, "__powikf2"); - symbol(&__powitf2, "__powitf2"); symbol(&__powixf2, "__powixf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__powitf2, "__powikf2"); + } else { + symbol(&__powitf2, "__powitf2"); + } } inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT { @@ -32,26 +34,41 @@ inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT { return if (is_recip) 1 / r else r; } -pub fn __powihf2(a: f16, b: i32) callconv(.c) f16 { +fn __powihf2(a: compiler_rt.f16.Abi, b: i32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(powi_f16(compiler_rt.f16.fromAbi(a), b)); +} +pub fn powi_f16(a: f16, b: i32) f16 { return powiXf2(f16, a, b); } -pub fn __powisf2(a: f32, b: i32) callconv(.c) f32 { +fn __powisf2(a: compiler_rt.f32.Abi, b: i32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(powi_f32(compiler_rt.f32.fromAbi(a), b)); +} +pub fn powi_f32(a: f32, b: i32) f32 { return powiXf2(f32, a, b); } -pub fn __powidf2(a: f64, b: i32) callconv(.c) f64 { +fn __powidf2(a: compiler_rt.f64.Abi, b: i32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(powi_f64(compiler_rt.f64.fromAbi(a), b)); +} +pub fn powi_f64(a: f64, b: i32) f64 { return powiXf2(f64, a, b); } -pub fn __powitf2(a: f128, b: i32) callconv(.c) f128 { - return powiXf2(f128, a, b); +fn __powixf2(a: compiler_rt.f80.Abi, b: i32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(powi_f80(compiler_rt.f80.fromAbi(a), b)); } - -pub fn __powixf2(a: f80, b: i32) callconv(.c) f80 { +pub fn powi_f80(a: f80, b: i32) f80 { return powiXf2(f80, a, b); } +fn __powitf2(a: compiler_rt.f128.Abi, b: i32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(powi_f128(compiler_rt.f128.fromAbi(a), b)); +} +pub fn powi_f128(a: f128, b: i32) f128 { + return powiXf2(f128, a, b); +} + test { _ = @import("powiXf2_test.zig"); } diff --git a/lib/compiler_rt/powiXf2_test.zig b/lib/compiler_rt/powiXf2_test.zig index 7bd43c73c3d2d1a379a6ef66977c55dff1fc8a00..1388a4e7250e7b418fee08cde6d165d2bce80adf 100644 --- a/lib/compiler_rt/powiXf2_test.zig +++ b/lib/compiler_rt/powiXf2_test.zig @@ -2,562 +2,568 @@ // powisf2_test.c, powidf2_test.c, powitf2_test.c, powixf2_test.c // powihf2 adapted from powisf2 tests -const powiXf2 = @import("powiXf2.zig"); const std = @import("std"); -const builtin = @import("builtin"); const testing = std.testing; const math = std.math; -fn test__powihf2(a: f16, b: i32, expected: f16) !void { - const result = powiXf2.__powihf2(a, b); +const impl = @import("powiXf2.zig"); + +const powi_f16 = impl.powi_f16; +const powi_f32 = impl.powi_f32; +const powi_f64 = impl.powi_f64; +const powi_f80 = impl.powi_f80; +const powi_f128 = impl.powi_f128; + +fn test_powi_f16(a: f16, b: i32, expected: f16) !void { + const result = powi_f16(a, b); try testing.expectEqual(expected, result); } -fn test__powisf2(a: f32, b: i32, expected: f32) !void { - const result = powiXf2.__powisf2(a, b); +fn test_powi_f32(a: f32, b: i32, expected: f32) !void { + const result = powi_f32(a, b); try testing.expectEqual(expected, result); } -fn test__powidf2(a: f64, b: i32, expected: f64) !void { - const result = powiXf2.__powidf2(a, b); +fn test_powi_f64(a: f64, b: i32, expected: f64) !void { + const result = powi_f64(a, b); try testing.expectEqual(expected, result); } -fn test__powitf2(a: f128, b: i32, expected: f128) !void { - const result = powiXf2.__powitf2(a, b); +fn test_powi_f80(a: f80, b: i32, expected: f80) !void { + const result = powi_f80(a, b); try testing.expectEqual(expected, result); } -fn test__powixf2(a: f80, b: i32, expected: f80) !void { - const result = powiXf2.__powixf2(a, b); +fn test_powi_f128(a: f128, b: i32, expected: f128) !void { + const result = powi_f128(a, b); try testing.expectEqual(expected, result); } -test "powihf2" { +test powi_f16 { const inf_f16 = math.inf(f16); - try test__powisf2(0, 0, 1); - try test__powihf2(1, 0, 1); - try test__powihf2(1.5, 0, 1); - try test__powihf2(2, 0, 1); - try test__powihf2(inf_f16, 0, 1); + try test_powi_f16(0, 0, 1); + try test_powi_f16(1, 0, 1); + try test_powi_f16(1.5, 0, 1); + try test_powi_f16(2, 0, 1); + try test_powi_f16(inf_f16, 0, 1); - try test__powihf2(-0.0, 0, 1); - try test__powihf2(-1, 0, 1); - try test__powihf2(-1.5, 0, 1); - try test__powihf2(-2, 0, 1); - try test__powihf2(-inf_f16, 0, 1); + try test_powi_f16(-0.0, 0, 1); + try test_powi_f16(-1, 0, 1); + try test_powi_f16(-1.5, 0, 1); + try test_powi_f16(-2, 0, 1); + try test_powi_f16(-inf_f16, 0, 1); - try test__powihf2(0, 1, 0); - try test__powihf2(0, 2, 0); - try test__powihf2(0, 3, 0); - try test__powihf2(0, 4, 0); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + try test_powi_f16(0, 1, 0); + try test_powi_f16(0, 2, 0); + try test_powi_f16(0, 3, 0); + try test_powi_f16(0, 4, 0); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - try test__powihf2(-0.0, 1, -0.0); - try test__powihf2(-0.0, 2, 0); - try test__powihf2(-0.0, 3, -0.0); - try test__powihf2(-0.0, 4, 0); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + try test_powi_f16(-0.0, 1, -0.0); + try test_powi_f16(-0.0, 2, 0); + try test_powi_f16(-0.0, 3, -0.0); + try test_powi_f16(-0.0, 4, 0); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - try test__powihf2(1, 1, 1); - try test__powihf2(1, 2, 1); - try test__powihf2(1, 3, 1); - try test__powihf2(1, 4, 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + try test_powi_f16(1, 1, 1); + try test_powi_f16(1, 2, 1); + try test_powi_f16(1, 3, 1); + try test_powi_f16(1, 4, 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - try test__powihf2(inf_f16, 1, inf_f16); - try test__powihf2(inf_f16, 2, inf_f16); - try test__powihf2(inf_f16, 3, inf_f16); - try test__powihf2(inf_f16, 4, inf_f16); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f16); + try test_powi_f16(inf_f16, 1, inf_f16); + try test_powi_f16(inf_f16, 2, inf_f16); + try test_powi_f16(inf_f16, 3, inf_f16); + try test_powi_f16(inf_f16, 4, inf_f16); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f16); - try test__powihf2(-inf_f16, 1, -inf_f16); - try test__powihf2(-inf_f16, 2, inf_f16); - try test__powihf2(-inf_f16, 3, -inf_f16); - try test__powihf2(-inf_f16, 4, inf_f16); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f16); + try test_powi_f16(-inf_f16, 1, -inf_f16); + try test_powi_f16(-inf_f16, 2, inf_f16); + try test_powi_f16(-inf_f16, 3, -inf_f16); + try test_powi_f16(-inf_f16, 4, inf_f16); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f16); // - try test__powihf2(0, -1, inf_f16); - try test__powihf2(0, -2, inf_f16); - try test__powihf2(0, -3, inf_f16); - try test__powihf2(0, -4, inf_f16); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // 0 ^ anything = +inf - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f16); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); + try test_powi_f16(0, -1, inf_f16); + try test_powi_f16(0, -2, inf_f16); + try test_powi_f16(0, -3, inf_f16); + try test_powi_f16(0, -4, inf_f16); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // 0 ^ anything = +inf + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f16); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); - try test__powihf2(-0.0, -1, -inf_f16); - try test__powihf2(-0.0, -2, inf_f16); - try test__powihf2(-0.0, -3, -inf_f16); - try test__powihf2(-0.0, -4, inf_f16); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // -0 ^ anything even = +inf - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f16); // -0 ^ anything odd = -inf - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); + try test_powi_f16(-0.0, -1, -inf_f16); + try test_powi_f16(-0.0, -2, inf_f16); + try test_powi_f16(-0.0, -3, -inf_f16); + try test_powi_f16(-0.0, -4, inf_f16); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // -0 ^ anything even = +inf + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f16); // -0 ^ anything odd = -inf + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); - try test__powihf2(1, -1, 1); - try test__powihf2(1, -2, 1); - try test__powihf2(1, -3, 1); - try test__powihf2(1, -4, 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); // 1.0 ^ anything = 1 - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + try test_powi_f16(1, -1, 1); + try test_powi_f16(1, -2, 1); + try test_powi_f16(1, -3, 1); + try test_powi_f16(1, -4, 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); // 1.0 ^ anything = 1 + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - try test__powihf2(inf_f16, -1, 0); - try test__powihf2(inf_f16, -2, 0); - try test__powihf2(inf_f16, -3, 0); - try test__powihf2(inf_f16, -4, 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f16(inf_f16, -1, 0); + try test_powi_f16(inf_f16, -2, 0); + try test_powi_f16(inf_f16, -3, 0); + try test_powi_f16(inf_f16, -4, 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); // - try test__powihf2(-inf_f16, -1, -0.0); - try test__powihf2(-inf_f16, -2, 0); - try test__powihf2(-inf_f16, -3, -0.0); - try test__powihf2(-inf_f16, -4, 0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f16(-inf_f16, -1, -0.0); + try test_powi_f16(-inf_f16, -2, 0); + try test_powi_f16(-inf_f16, -3, -0.0); + try test_powi_f16(-inf_f16, -4, 0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powihf2(2, 10, 1024.0); - try test__powihf2(-2, 10, 1024.0); - try test__powihf2(2, -10, 1.0 / 1024.0); - try test__powihf2(-2, -10, 1.0 / 1024.0); + try test_powi_f16(2, 10, 1024.0); + try test_powi_f16(-2, 10, 1024.0); + try test_powi_f16(2, -10, 1.0 / 1024.0); + try test_powi_f16(-2, -10, 1.0 / 1024.0); - try test__powihf2(2, 14, 16384.0); - try test__powihf2(-2, 14, 16384.0); - try test__powihf2(2, 15, 32768.0); - try test__powihf2(-2, 15, -32768.0); - try test__powihf2(2, 16, inf_f16); - try test__powihf2(-2, 16, inf_f16); + try test_powi_f16(2, 14, 16384.0); + try test_powi_f16(-2, 14, 16384.0); + try test_powi_f16(2, 15, 32768.0); + try test_powi_f16(-2, 15, -32768.0); + try test_powi_f16(2, 16, inf_f16); + try test_powi_f16(-2, 16, inf_f16); - try test__powihf2(2, -13, 1.0 / 8192.0); - try test__powihf2(-2, -13, -1.0 / 8192.0); - try test__powihf2(2, -15, 1.0 / 32768.0); - try test__powihf2(-2, -15, -1.0 / 32768.0); - try test__powihf2(2, -16, 0.0); // expected = 0.0 = 1/(-2**16) - try test__powihf2(-2, -16, 0.0); // expected = 0.0 = 1/(2**16) + try test_powi_f16(2, -13, 1.0 / 8192.0); + try test_powi_f16(-2, -13, -1.0 / 8192.0); + try test_powi_f16(2, -15, 1.0 / 32768.0); + try test_powi_f16(-2, -15, -1.0 / 32768.0); + try test_powi_f16(2, -16, 0.0); // expected = 0.0 = 1/(-2**16) + try test_powi_f16(-2, -16, 0.0); // expected = 0.0 = 1/(2**16) } -test "powisf2" { +test powi_f32 { const inf_f32 = math.inf(f32); - try test__powisf2(0, 0, 1); - try test__powisf2(1, 0, 1); - try test__powisf2(1.5, 0, 1); - try test__powisf2(2, 0, 1); - try test__powisf2(inf_f32, 0, 1); + try test_powi_f32(0, 0, 1); + try test_powi_f32(1, 0, 1); + try test_powi_f32(1.5, 0, 1); + try test_powi_f32(2, 0, 1); + try test_powi_f32(inf_f32, 0, 1); - try test__powisf2(-0.0, 0, 1); - try test__powisf2(-1, 0, 1); - try test__powisf2(-1.5, 0, 1); - try test__powisf2(-2, 0, 1); - try test__powisf2(-inf_f32, 0, 1); + try test_powi_f32(-0.0, 0, 1); + try test_powi_f32(-1, 0, 1); + try test_powi_f32(-1.5, 0, 1); + try test_powi_f32(-2, 0, 1); + try test_powi_f32(-inf_f32, 0, 1); - try test__powisf2(0, 1, 0); - try test__powisf2(0, 2, 0); - try test__powisf2(0, 3, 0); - try test__powisf2(0, 4, 0); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + try test_powi_f32(0, 1, 0); + try test_powi_f32(0, 2, 0); + try test_powi_f32(0, 3, 0); + try test_powi_f32(0, 4, 0); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - try test__powisf2(-0.0, 1, -0.0); - try test__powisf2(-0.0, 2, 0); - try test__powisf2(-0.0, 3, -0.0); - try test__powisf2(-0.0, 4, 0); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + try test_powi_f32(-0.0, 1, -0.0); + try test_powi_f32(-0.0, 2, 0); + try test_powi_f32(-0.0, 3, -0.0); + try test_powi_f32(-0.0, 4, 0); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - try test__powisf2(1, 1, 1); - try test__powisf2(1, 2, 1); - try test__powisf2(1, 3, 1); - try test__powisf2(1, 4, 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + try test_powi_f32(1, 1, 1); + try test_powi_f32(1, 2, 1); + try test_powi_f32(1, 3, 1); + try test_powi_f32(1, 4, 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - try test__powisf2(inf_f32, 1, inf_f32); - try test__powisf2(inf_f32, 2, inf_f32); - try test__powisf2(inf_f32, 3, inf_f32); - try test__powisf2(inf_f32, 4, inf_f32); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f32); + try test_powi_f32(inf_f32, 1, inf_f32); + try test_powi_f32(inf_f32, 2, inf_f32); + try test_powi_f32(inf_f32, 3, inf_f32); + try test_powi_f32(inf_f32, 4, inf_f32); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f32); - try test__powisf2(-inf_f32, 1, -inf_f32); - try test__powisf2(-inf_f32, 2, inf_f32); - try test__powisf2(-inf_f32, 3, -inf_f32); - try test__powisf2(-inf_f32, 4, inf_f32); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f32); + try test_powi_f32(-inf_f32, 1, -inf_f32); + try test_powi_f32(-inf_f32, 2, inf_f32); + try test_powi_f32(-inf_f32, 3, -inf_f32); + try test_powi_f32(-inf_f32, 4, inf_f32); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f32); - try test__powisf2(0, -1, inf_f32); - try test__powisf2(0, -2, inf_f32); - try test__powisf2(0, -3, inf_f32); - try test__powisf2(0, -4, inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); + try test_powi_f32(0, -1, inf_f32); + try test_powi_f32(0, -2, inf_f32); + try test_powi_f32(0, -3, inf_f32); + try test_powi_f32(0, -4, inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); - try test__powisf2(-0.0, -1, -inf_f32); - try test__powisf2(-0.0, -2, inf_f32); - try test__powisf2(-0.0, -3, -inf_f32); - try test__powisf2(-0.0, -4, inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); + try test_powi_f32(-0.0, -1, -inf_f32); + try test_powi_f32(-0.0, -2, inf_f32); + try test_powi_f32(-0.0, -3, -inf_f32); + try test_powi_f32(-0.0, -4, inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); - try test__powisf2(1, -1, 1); - try test__powisf2(1, -2, 1); - try test__powisf2(1, -3, 1); - try test__powisf2(1, -4, 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + try test_powi_f32(1, -1, 1); + try test_powi_f32(1, -2, 1); + try test_powi_f32(1, -3, 1); + try test_powi_f32(1, -4, 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - try test__powisf2(inf_f32, -1, 0); - try test__powisf2(inf_f32, -2, 0); - try test__powisf2(inf_f32, -3, 0); - try test__powisf2(inf_f32, -4, 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f32(inf_f32, -1, 0); + try test_powi_f32(inf_f32, -2, 0); + try test_powi_f32(inf_f32, -3, 0); + try test_powi_f32(inf_f32, -4, 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powisf2(-inf_f32, -1, -0.0); - try test__powisf2(-inf_f32, -2, 0); - try test__powisf2(-inf_f32, -3, -0.0); - try test__powisf2(-inf_f32, -4, 0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f32(-inf_f32, -1, -0.0); + try test_powi_f32(-inf_f32, -2, 0); + try test_powi_f32(-inf_f32, -3, -0.0); + try test_powi_f32(-inf_f32, -4, 0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powisf2(2.0, 10, 1024.0); - try test__powisf2(-2, 10, 1024.0); - try test__powisf2(2, -10, 1.0 / 1024.0); - try test__powisf2(-2, -10, 1.0 / 1024.0); + try test_powi_f32(2.0, 10, 1024.0); + try test_powi_f32(-2, 10, 1024.0); + try test_powi_f32(2, -10, 1.0 / 1024.0); + try test_powi_f32(-2, -10, 1.0 / 1024.0); // - try test__powisf2(2, 19, 524288.0); - try test__powisf2(-2, 19, -524288.0); - try test__powisf2(2, -19, 1.0 / 524288.0); - try test__powisf2(-2, -19, -1.0 / 524288.0); + try test_powi_f32(2, 19, 524288.0); + try test_powi_f32(-2, 19, -524288.0); + try test_powi_f32(2, -19, 1.0 / 524288.0); + try test_powi_f32(-2, -19, -1.0 / 524288.0); - try test__powisf2(2, 31, 2147483648.0); - try test__powisf2(-2, 31, -2147483648.0); - try test__powisf2(2, -31, 1.0 / 2147483648.0); - try test__powisf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f32(2, 31, 2147483648.0); + try test_powi_f32(-2, 31, -2147483648.0); + try test_powi_f32(2, -31, 1.0 / 2147483648.0); + try test_powi_f32(-2, -31, -1.0 / 2147483648.0); } -test "powidf2" { +test powi_f64 { const inf_f64 = math.inf(f64); - try test__powidf2(0, 0, 1); - try test__powidf2(1, 0, 1); - try test__powidf2(1.5, 0, 1); - try test__powidf2(2, 0, 1); - try test__powidf2(inf_f64, 0, 1); - - try test__powidf2(-0.0, 0, 1); - try test__powidf2(-1, 0, 1); - try test__powidf2(-1.5, 0, 1); - try test__powidf2(-2, 0, 1); - try test__powidf2(-inf_f64, 0, 1); - - try test__powidf2(0, 1, 0); - try test__powidf2(0, 2, 0); - try test__powidf2(0, 3, 0); - try test__powidf2(0, 4, 0); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - - try test__powidf2(-0.0, 1, -0.0); - try test__powidf2(-0.0, 2, 0); - try test__powidf2(-0.0, 3, -0.0); - try test__powidf2(-0.0, 4, 0); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powidf2(1, 1, 1); - try test__powidf2(1, 2, 1); - try test__powidf2(1, 3, 1); - try test__powidf2(1, 4, 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powidf2(inf_f64, 1, inf_f64); - try test__powidf2(inf_f64, 2, inf_f64); - try test__powidf2(inf_f64, 3, inf_f64); - try test__powidf2(inf_f64, 4, inf_f64); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f64); - - try test__powidf2(-inf_f64, 1, -inf_f64); - try test__powidf2(-inf_f64, 2, inf_f64); - try test__powidf2(-inf_f64, 3, -inf_f64); - try test__powidf2(-inf_f64, 4, inf_f64); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f64); - - try test__powidf2(0, -1, inf_f64); - try test__powidf2(0, -2, inf_f64); - try test__powidf2(0, -3, inf_f64); - try test__powidf2(0, -4, inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); - - try test__powidf2(-0.0, -1, -inf_f64); - try test__powidf2(-0.0, -2, inf_f64); - try test__powidf2(-0.0, -3, -inf_f64); - try test__powidf2(-0.0, -4, inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); - - try test__powidf2(1, -1, 1); - try test__powidf2(1, -2, 1); - try test__powidf2(1, -3, 1); - try test__powidf2(1, -4, 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powidf2(inf_f64, -1, 0); - try test__powidf2(inf_f64, -2, 0); - try test__powidf2(inf_f64, -3, 0); - try test__powidf2(inf_f64, -4, 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powidf2(-inf_f64, -1, -0.0); - try test__powidf2(-inf_f64, -2, 0); - try test__powidf2(-inf_f64, -3, -0.0); - try test__powidf2(-inf_f64, -4, 0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powidf2(2, 10, 1024.0); - try test__powidf2(-2, 10, 1024.0); - try test__powidf2(2, -10, 1.0 / 1024.0); - try test__powidf2(-2, -10, 1.0 / 1024.0); - - try test__powidf2(2, 19, 524288.0); - try test__powidf2(-2, 19, -524288.0); - try test__powidf2(2, -19, 1.0 / 524288.0); - try test__powidf2(-2, -19, -1.0 / 524288.0); - - try test__powidf2(2, 31, 2147483648.0); - try test__powidf2(-2, 31, -2147483648.0); - try test__powidf2(2, -31, 1.0 / 2147483648.0); - try test__powidf2(-2, -31, -1.0 / 2147483648.0); -} - -test "powitf2" { - const inf_f128 = math.inf(f128); - try test__powitf2(0, 0, 1); - try test__powitf2(1, 0, 1); - try test__powitf2(1.5, 0, 1); - try test__powitf2(2, 0, 1); - try test__powitf2(inf_f128, 0, 1); - - try test__powitf2(-0.0, 0, 1); - try test__powitf2(-1, 0, 1); - try test__powitf2(-1.5, 0, 1); - try test__powitf2(-2, 0, 1); - try test__powitf2(-inf_f128, 0, 1); - - try test__powitf2(0, 1, 0); - try test__powitf2(0, 2, 0); - try test__powitf2(0, 3, 0); - try test__powitf2(0, 4, 0); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powitf2(0, 0x7FFFFFFF, 0); - - try test__powitf2(-0.0, 1, -0.0); - try test__powitf2(-0.0, 2, 0); - try test__powitf2(-0.0, 3, -0.0); - try test__powitf2(-0.0, 4, 0); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powitf2(1, 1, 1); - try test__powitf2(1, 2, 1); - try test__powitf2(1, 3, 1); - try test__powitf2(1, 4, 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powitf2(inf_f128, 1, inf_f128); - try test__powitf2(inf_f128, 2, inf_f128); - try test__powitf2(inf_f128, 3, inf_f128); - try test__powitf2(inf_f128, 4, inf_f128); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f128); - - try test__powitf2(-inf_f128, 1, -inf_f128); - try test__powitf2(-inf_f128, 2, inf_f128); - try test__powitf2(-inf_f128, 3, -inf_f128); - try test__powitf2(-inf_f128, 4, inf_f128); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f128); - - try test__powitf2(0, -1, inf_f128); - try test__powitf2(0, -2, inf_f128); - try test__powitf2(0, -3, inf_f128); - try test__powitf2(0, -4, inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); - - try test__powitf2(-0.0, -1, -inf_f128); - try test__powitf2(-0.0, -2, inf_f128); - try test__powitf2(-0.0, -3, -inf_f128); - try test__powitf2(-0.0, -4, inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); - - try test__powitf2(1, -1, 1); - try test__powitf2(1, -2, 1); - try test__powitf2(1, -3, 1); - try test__powitf2(1, -4, 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powitf2(inf_f128, -1, 0); - try test__powitf2(inf_f128, -2, 0); - try test__powitf2(inf_f128, -3, 0); - try test__powitf2(inf_f128, -4, 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powitf2(-inf_f128, -1, -0.0); - try test__powitf2(-inf_f128, -2, 0); - try test__powitf2(-inf_f128, -3, -0.0); - try test__powitf2(-inf_f128, -4, 0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powitf2(2, 10, 1024.0); - try test__powitf2(-2, 10, 1024.0); - try test__powitf2(2, -10, 1.0 / 1024.0); - try test__powitf2(-2, -10, 1.0 / 1024.0); - - try test__powitf2(2, 19, 524288.0); - try test__powitf2(-2, 19, -524288.0); - try test__powitf2(2, -19, 1.0 / 524288.0); - try test__powitf2(-2, -19, -1.0 / 524288.0); - - try test__powitf2(2, 31, 2147483648.0); - try test__powitf2(-2, 31, -2147483648.0); - try test__powitf2(2, -31, 1.0 / 2147483648.0); - try test__powitf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f64(0, 0, 1); + try test_powi_f64(1, 0, 1); + try test_powi_f64(1.5, 0, 1); + try test_powi_f64(2, 0, 1); + try test_powi_f64(inf_f64, 0, 1); + + try test_powi_f64(-0.0, 0, 1); + try test_powi_f64(-1, 0, 1); + try test_powi_f64(-1.5, 0, 1); + try test_powi_f64(-2, 0, 1); + try test_powi_f64(-inf_f64, 0, 1); + + try test_powi_f64(0, 1, 0); + try test_powi_f64(0, 2, 0); + try test_powi_f64(0, 3, 0); + try test_powi_f64(0, 4, 0); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + + try test_powi_f64(-0.0, 1, -0.0); + try test_powi_f64(-0.0, 2, 0); + try test_powi_f64(-0.0, 3, -0.0); + try test_powi_f64(-0.0, 4, 0); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f64(1, 1, 1); + try test_powi_f64(1, 2, 1); + try test_powi_f64(1, 3, 1); + try test_powi_f64(1, 4, 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f64(inf_f64, 1, inf_f64); + try test_powi_f64(inf_f64, 2, inf_f64); + try test_powi_f64(inf_f64, 3, inf_f64); + try test_powi_f64(inf_f64, 4, inf_f64); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f64); + + try test_powi_f64(-inf_f64, 1, -inf_f64); + try test_powi_f64(-inf_f64, 2, inf_f64); + try test_powi_f64(-inf_f64, 3, -inf_f64); + try test_powi_f64(-inf_f64, 4, inf_f64); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f64); + + try test_powi_f64(0, -1, inf_f64); + try test_powi_f64(0, -2, inf_f64); + try test_powi_f64(0, -3, inf_f64); + try test_powi_f64(0, -4, inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); + + try test_powi_f64(-0.0, -1, -inf_f64); + try test_powi_f64(-0.0, -2, inf_f64); + try test_powi_f64(-0.0, -3, -inf_f64); + try test_powi_f64(-0.0, -4, inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); + + try test_powi_f64(1, -1, 1); + try test_powi_f64(1, -2, 1); + try test_powi_f64(1, -3, 1); + try test_powi_f64(1, -4, 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f64(inf_f64, -1, 0); + try test_powi_f64(inf_f64, -2, 0); + try test_powi_f64(inf_f64, -3, 0); + try test_powi_f64(inf_f64, -4, 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f64(-inf_f64, -1, -0.0); + try test_powi_f64(-inf_f64, -2, 0); + try test_powi_f64(-inf_f64, -3, -0.0); + try test_powi_f64(-inf_f64, -4, 0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f64(2, 10, 1024.0); + try test_powi_f64(-2, 10, 1024.0); + try test_powi_f64(2, -10, 1.0 / 1024.0); + try test_powi_f64(-2, -10, 1.0 / 1024.0); + + try test_powi_f64(2, 19, 524288.0); + try test_powi_f64(-2, 19, -524288.0); + try test_powi_f64(2, -19, 1.0 / 524288.0); + try test_powi_f64(-2, -19, -1.0 / 524288.0); + + try test_powi_f64(2, 31, 2147483648.0); + try test_powi_f64(-2, 31, -2147483648.0); + try test_powi_f64(2, -31, 1.0 / 2147483648.0); + try test_powi_f64(-2, -31, -1.0 / 2147483648.0); } -test "powixf2" { +test powi_f80 { const inf_f80 = math.inf(f80); - try test__powixf2(0, 0, 1); - try test__powixf2(1, 0, 1); - try test__powixf2(1.5, 0, 1); - try test__powixf2(2, 0, 1); - try test__powixf2(inf_f80, 0, 1); - - try test__powixf2(-0.0, 0, 1); - try test__powixf2(-1, 0, 1); - try test__powixf2(-1.5, 0, 1); - try test__powixf2(-2, 0, 1); - try test__powixf2(-inf_f80, 0, 1); - - try test__powixf2(0, 1, 0); - try test__powixf2(0, 2, 0); - try test__powixf2(0, 3, 0); - try test__powixf2(0, 4, 0); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - - try test__powixf2(-0.0, 1, -0.0); - try test__powixf2(-0.0, 2, 0); - try test__powixf2(-0.0, 3, -0.0); - try test__powixf2(-0.0, 4, 0); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powixf2(1, 1, 1); - try test__powixf2(1, 2, 1); - try test__powixf2(1, 3, 1); - try test__powixf2(1, 4, 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powixf2(inf_f80, 1, inf_f80); - try test__powixf2(inf_f80, 2, inf_f80); - try test__powixf2(inf_f80, 3, inf_f80); - try test__powixf2(inf_f80, 4, inf_f80); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f80); - - try test__powixf2(-inf_f80, 1, -inf_f80); - try test__powixf2(-inf_f80, 2, inf_f80); - try test__powixf2(-inf_f80, 3, -inf_f80); - try test__powixf2(-inf_f80, 4, inf_f80); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f80); - - try test__powixf2(0, -1, inf_f80); - try test__powixf2(0, -2, inf_f80); - try test__powixf2(0, -3, inf_f80); - try test__powixf2(0, -4, inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); - - try test__powixf2(-0.0, -1, -inf_f80); - try test__powixf2(-0.0, -2, inf_f80); - try test__powixf2(-0.0, -3, -inf_f80); - try test__powixf2(-0.0, -4, inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); - - try test__powixf2(1, -1, 1); - try test__powixf2(1, -2, 1); - try test__powixf2(1, -3, 1); - try test__powixf2(1, -4, 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powixf2(inf_f80, -1, 0); - try test__powixf2(inf_f80, -2, 0); - try test__powixf2(inf_f80, -3, 0); - try test__powixf2(inf_f80, -4, 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powixf2(-inf_f80, -1, -0.0); - try test__powixf2(-inf_f80, -2, 0); - try test__powixf2(-inf_f80, -3, -0.0); - try test__powixf2(-inf_f80, -4, 0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powixf2(2, 10, 1024.0); - try test__powixf2(-2, 10, 1024.0); - try test__powixf2(2, -10, 1.0 / 1024.0); - try test__powixf2(-2, -10, 1.0 / 1024.0); - - try test__powixf2(2, 19, 524288.0); - try test__powixf2(-2, 19, -524288.0); - try test__powixf2(2, -19, 1.0 / 524288.0); - try test__powixf2(-2, -19, -1.0 / 524288.0); - - try test__powixf2(2, 31, 2147483648.0); - try test__powixf2(-2, 31, -2147483648.0); - try test__powixf2(2, -31, 1.0 / 2147483648.0); - try test__powixf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f80(0, 0, 1); + try test_powi_f80(1, 0, 1); + try test_powi_f80(1.5, 0, 1); + try test_powi_f80(2, 0, 1); + try test_powi_f80(inf_f80, 0, 1); + + try test_powi_f80(-0.0, 0, 1); + try test_powi_f80(-1, 0, 1); + try test_powi_f80(-1.5, 0, 1); + try test_powi_f80(-2, 0, 1); + try test_powi_f80(-inf_f80, 0, 1); + + try test_powi_f80(0, 1, 0); + try test_powi_f80(0, 2, 0); + try test_powi_f80(0, 3, 0); + try test_powi_f80(0, 4, 0); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + + try test_powi_f80(-0.0, 1, -0.0); + try test_powi_f80(-0.0, 2, 0); + try test_powi_f80(-0.0, 3, -0.0); + try test_powi_f80(-0.0, 4, 0); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f80(1, 1, 1); + try test_powi_f80(1, 2, 1); + try test_powi_f80(1, 3, 1); + try test_powi_f80(1, 4, 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f80(inf_f80, 1, inf_f80); + try test_powi_f80(inf_f80, 2, inf_f80); + try test_powi_f80(inf_f80, 3, inf_f80); + try test_powi_f80(inf_f80, 4, inf_f80); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f80); + + try test_powi_f80(-inf_f80, 1, -inf_f80); + try test_powi_f80(-inf_f80, 2, inf_f80); + try test_powi_f80(-inf_f80, 3, -inf_f80); + try test_powi_f80(-inf_f80, 4, inf_f80); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f80); + + try test_powi_f80(0, -1, inf_f80); + try test_powi_f80(0, -2, inf_f80); + try test_powi_f80(0, -3, inf_f80); + try test_powi_f80(0, -4, inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); + + try test_powi_f80(-0.0, -1, -inf_f80); + try test_powi_f80(-0.0, -2, inf_f80); + try test_powi_f80(-0.0, -3, -inf_f80); + try test_powi_f80(-0.0, -4, inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); + + try test_powi_f80(1, -1, 1); + try test_powi_f80(1, -2, 1); + try test_powi_f80(1, -3, 1); + try test_powi_f80(1, -4, 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f80(inf_f80, -1, 0); + try test_powi_f80(inf_f80, -2, 0); + try test_powi_f80(inf_f80, -3, 0); + try test_powi_f80(inf_f80, -4, 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f80(-inf_f80, -1, -0.0); + try test_powi_f80(-inf_f80, -2, 0); + try test_powi_f80(-inf_f80, -3, -0.0); + try test_powi_f80(-inf_f80, -4, 0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f80(2, 10, 1024.0); + try test_powi_f80(-2, 10, 1024.0); + try test_powi_f80(2, -10, 1.0 / 1024.0); + try test_powi_f80(-2, -10, 1.0 / 1024.0); + + try test_powi_f80(2, 19, 524288.0); + try test_powi_f80(-2, 19, -524288.0); + try test_powi_f80(2, -19, 1.0 / 524288.0); + try test_powi_f80(-2, -19, -1.0 / 524288.0); + + try test_powi_f80(2, 31, 2147483648.0); + try test_powi_f80(-2, 31, -2147483648.0); + try test_powi_f80(2, -31, 1.0 / 2147483648.0); + try test_powi_f80(-2, -31, -1.0 / 2147483648.0); +} + +test powi_f128 { + const inf_f128 = math.inf(f128); + try test_powi_f128(0, 0, 1); + try test_powi_f128(1, 0, 1); + try test_powi_f128(1.5, 0, 1); + try test_powi_f128(2, 0, 1); + try test_powi_f128(inf_f128, 0, 1); + + try test_powi_f128(-0.0, 0, 1); + try test_powi_f128(-1, 0, 1); + try test_powi_f128(-1.5, 0, 1); + try test_powi_f128(-2, 0, 1); + try test_powi_f128(-inf_f128, 0, 1); + + try test_powi_f128(0, 1, 0); + try test_powi_f128(0, 2, 0); + try test_powi_f128(0, 3, 0); + try test_powi_f128(0, 4, 0); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f128(0, 0x7FFFFFFF, 0); + + try test_powi_f128(-0.0, 1, -0.0); + try test_powi_f128(-0.0, 2, 0); + try test_powi_f128(-0.0, 3, -0.0); + try test_powi_f128(-0.0, 4, 0); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f128(1, 1, 1); + try test_powi_f128(1, 2, 1); + try test_powi_f128(1, 3, 1); + try test_powi_f128(1, 4, 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f128(inf_f128, 1, inf_f128); + try test_powi_f128(inf_f128, 2, inf_f128); + try test_powi_f128(inf_f128, 3, inf_f128); + try test_powi_f128(inf_f128, 4, inf_f128); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f128); + + try test_powi_f128(-inf_f128, 1, -inf_f128); + try test_powi_f128(-inf_f128, 2, inf_f128); + try test_powi_f128(-inf_f128, 3, -inf_f128); + try test_powi_f128(-inf_f128, 4, inf_f128); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f128); + + try test_powi_f128(0, -1, inf_f128); + try test_powi_f128(0, -2, inf_f128); + try test_powi_f128(0, -3, inf_f128); + try test_powi_f128(0, -4, inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); + + try test_powi_f128(-0.0, -1, -inf_f128); + try test_powi_f128(-0.0, -2, inf_f128); + try test_powi_f128(-0.0, -3, -inf_f128); + try test_powi_f128(-0.0, -4, inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); + + try test_powi_f128(1, -1, 1); + try test_powi_f128(1, -2, 1); + try test_powi_f128(1, -3, 1); + try test_powi_f128(1, -4, 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f128(inf_f128, -1, 0); + try test_powi_f128(inf_f128, -2, 0); + try test_powi_f128(inf_f128, -3, 0); + try test_powi_f128(inf_f128, -4, 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f128(-inf_f128, -1, -0.0); + try test_powi_f128(-inf_f128, -2, 0); + try test_powi_f128(-inf_f128, -3, -0.0); + try test_powi_f128(-inf_f128, -4, 0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f128(2, 10, 1024.0); + try test_powi_f128(-2, 10, 1024.0); + try test_powi_f128(2, -10, 1.0 / 1024.0); + try test_powi_f128(-2, -10, 1.0 / 1024.0); + + try test_powi_f128(2, 19, 524288.0); + try test_powi_f128(-2, 19, -524288.0); + try test_powi_f128(2, -19, 1.0 / 524288.0); + try test_powi_f128(-2, -19, -1.0 / 524288.0); + + try test_powi_f128(2, 31, 2147483648.0); + try test_powi_f128(-2, 31, -2147483648.0); + try test_powi_f128(2, -31, 1.0 / 2147483648.0); + try test_powi_f128(-2, -31, -1.0 / 2147483648.0); } diff --git a/lib/compiler_rt/round.zig b/lib/compiler_rt/round.zig index 590b957922efdbf33ac4fea2728390daad82ee38..ffcaed60774e70e5067ff107380a8af5a057d718 100644 --- a/lib/compiler_rt/round.zig +++ b/lib/compiler_rt/round.zig @@ -18,19 +18,22 @@ comptime { symbol(&roundf, "roundf"); symbol(&round, "round"); symbol(&__roundx, "__roundx"); - if (compiler_rt.want_ppc_abi) { - symbol(&roundq, "roundf128"); - } - symbol(&roundq, "roundq"); + symbol(&roundq, "roundf128"); symbol(&roundl, "roundl"); } -pub fn __roundh(x: f16) callconv(.c) f16 { +fn __roundh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(round_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn round_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(roundf(x)); + return @floatCast(round_f32(x)); } -pub fn roundf(x_: f32) callconv(.c) f32 { +fn roundf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(round_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn round_f32(x_: f32) f32 { const f32_toint = 1.0 / math.floatEps(f32); var x = x_; @@ -65,7 +68,10 @@ pub fn roundf(x_: f32) callconv(.c) f32 { } } -pub fn round(x_: f64) callconv(.c) f64 { +fn round(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(round_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn round_f64(x_: f64) f64 { const f64_toint = 1.0 / math.floatEps(f64); var x = x_; @@ -100,12 +106,18 @@ pub fn round(x_: f64) callconv(.c) f64 { } } -pub fn __roundx(x: f80) callconv(.c) f80 { +fn __roundx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(round_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn round_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(roundq(x)); + return @floatCast(round_f128(x)); } -pub fn roundq(x_: f128) callconv(.c) f128 { +fn roundq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(round_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn round_f128(x_: f128) f128 { const f128_toint = 1.0 / math.floatEps(f128); var x = x_; @@ -142,54 +154,79 @@ pub fn roundq(x_: f128) callconv(.c) f128 { pub fn roundl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return round(x), - 80 => return __roundx(x), - 128 => return roundq(x), - else => @compileError("unreachable"), + 64 => return round_f64(x), + 80 => return round_f80(x), + 128 => return round_f128(x), + else => comptime unreachable, } } -test "round32" { - try expect(roundf(1.3) == 1.0); - try expect(roundf(-1.3) == -1.0); - try expect(roundf(0.2) == 0.0); - try expect(roundf(1.8) == 2.0); +test round_f16 { + try expect(round_f16(1.3) == 1.0); + try expect(round_f16(-1.3) == -1.0); + try expect(round_f16(1.8) == 2.0); + try expect(round_f16(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f16(0.2))); + try expect(math.isNegativeZero(round_f16(-0.2))); + try expect(math.isPositiveZero(round_f16(0.0))); + try expect(math.isNegativeZero(round_f16(-0.0))); + try expect(math.isPositiveInf(round_f16(math.inf(f32)))); + try expect(math.isNegativeInf(round_f16(-math.inf(f32)))); + try expect(math.isNan(round_f16(math.nan(f32)))); } -test "round64" { - try expect(round(1.3) == 1.0); - try expect(round(-1.3) == -1.0); - try expect(round(0.2) == 0.0); - try expect(round(1.8) == 2.0); +test round_f32 { + try expect(round_f32(1.3) == 1.0); + try expect(round_f32(-1.3) == -1.0); + try expect(round_f32(1.8) == 2.0); + try expect(round_f32(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f32(0.2))); + try expect(math.isNegativeZero(round_f32(-0.2))); + try expect(math.isPositiveZero(round_f32(0.0))); + try expect(math.isNegativeZero(round_f32(-0.0))); + try expect(math.isPositiveInf(round_f32(math.inf(f32)))); + try expect(math.isNegativeInf(round_f32(-math.inf(f32)))); + try expect(math.isNan(round_f32(math.nan(f32)))); } -test "round128" { - try expect(roundq(1.3) == 1.0); - try expect(roundq(-1.3) == -1.0); - try expect(roundq(0.2) == 0.0); - try expect(roundq(1.8) == 2.0); +test round_f64 { + try expect(round_f64(1.3) == 1.0); + try expect(round_f64(-1.3) == -1.0); + try expect(round_f64(1.8) == 2.0); + try expect(round_f64(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f64(0.2))); + try expect(math.isNegativeZero(round_f64(-0.2))); + try expect(math.isPositiveZero(round_f64(0.0))); + try expect(math.isNegativeZero(round_f64(-0.0))); + try expect(math.isPositiveInf(round_f64(math.inf(f64)))); + try expect(math.isNegativeInf(round_f64(-math.inf(f64)))); + try expect(math.isNan(round_f64(math.nan(f64)))); } -test "round32.special" { - try expect(roundf(0.0) == 0.0); - try expect(roundf(-0.0) == -0.0); - try expect(math.isPositiveInf(roundf(math.inf(f32)))); - try expect(math.isNegativeInf(roundf(-math.inf(f32)))); - try expect(math.isNan(roundf(math.nan(f32)))); +test round_f80 { + try expect(round_f80(1.3) == 1.0); + try expect(round_f80(-1.3) == -1.0); + try expect(round_f80(1.8) == 2.0); + try expect(round_f80(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f80(0.2))); + try expect(math.isNegativeZero(round_f80(-0.2))); + try expect(math.isPositiveZero(round_f80(0.0))); + try expect(math.isNegativeZero(round_f80(-0.0))); + try expect(math.isPositiveInf(round_f80(math.inf(f64)))); + try expect(math.isNegativeInf(round_f80(-math.inf(f64)))); + try expect(math.isNan(round_f80(math.nan(f64)))); } -test "round64.special" { - try expect(round(0.0) == 0.0); - try expect(round(-0.0) == -0.0); - try expect(math.isPositiveInf(round(math.inf(f64)))); - try expect(math.isNegativeInf(round(-math.inf(f64)))); - try expect(math.isNan(round(math.nan(f64)))); -} - -test "round128.special" { - try expect(roundq(0.0) == 0.0); - try expect(roundq(-0.0) == -0.0); - try expect(math.isPositiveInf(roundq(math.inf(f128)))); - try expect(math.isNegativeInf(roundq(-math.inf(f128)))); - try expect(math.isNan(roundq(math.nan(f128)))); +test round_f128 { + try expect(round_f128(1.3) == 1.0); + try expect(round_f128(-1.3) == -1.0); + try expect(round_f128(1.8) == 2.0); + try expect(round_f128(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f128(0.2))); + try expect(math.isNegativeZero(round_f128(-0.2))); + try expect(math.isPositiveZero(round_f128(0.0))); + try expect(math.isNegativeZero(round_f128(-0.0))); + try expect(math.isPositiveInf(round_f128(math.inf(f128)))); + try expect(math.isNegativeInf(round_f128(-math.inf(f128)))); + try expect(math.isNan(round_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/sin.zig b/lib/compiler_rt/sin.zig index 040cba8cd3ef34e59f6bfd181a3c09036963fb4c..3e0b8f0cbd823b0e57fe0172217c7726955c7fd1 100644 --- a/lib/compiler_rt/sin.zig +++ b/lib/compiler_rt/sin.zig @@ -13,31 +13,34 @@ const expect = std.testing.expect; const expectApproxEqAbs = std.testing.expectApproxEqAbs; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; comptime { - symbol(&sinh, "__sinh"); - symbol(&sinl, "__sinl"); + symbol(&__sinh, "__sinh"); symbol(&sinf, "sinf"); symbol(&sin, "sin"); - symbol(&sinx, "__sinx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sinq, "sinf128"); - } - symbol(&sinq, "sinq"); + symbol(&__sinx, "__sinx"); + symbol(&sinq, "sinf128"); symbol(&sinl, "sinl"); + symbol(&sinl, "__sinl"); // required by musl } -pub fn sinh(x: f16) callconv(.c) f16 { +fn __sinh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sin_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn sin_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(sinf(x)); + return @floatCast(sin_f32(x)); } -pub fn sinf(x: f32) callconv(.c) f32 { +fn sinf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sin_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn sin_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -98,7 +101,10 @@ pub fn sinf(x: f32) callconv(.c) f32 { }; } -pub fn sin(x: f64) callconv(.c) f64 { +fn sin(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sin_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn sin_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -133,7 +139,10 @@ pub fn sin(x: f64) callconv(.c) f64 { }; } -fn sinx(x: f80) callconv(.c) f80 { +fn __sinx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sin_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn sin_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -160,7 +169,10 @@ fn sinx(x: f80) callconv(.c) f80 { }; } -pub fn sinq(x: f128) callconv(.c) f128 { +fn sinq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sin_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn sin_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -189,20 +201,21 @@ pub fn sinq(x: f128) callconv(.c) f128 { pub fn sinl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sin(x), - 80 => return sinx(x), - 128 => return sinq(x), - else => @compileError("unreachable"), + 64 => return sin_f64(x), + 80 => return sin_f80(x), + 128 => return sin_f128(x), + else => comptime unreachable, } } fn testSinSpecial(comptime T: type) !void { const f = switch (T) { - f32 => sinf, - f64 => sin, - f80 => sinx, - f128 => sinq, - else => @compileError("unimplemented"), + f16 => sin_f16, + f32 => sin_f32, + f64 => sin_f64, + f80 => sin_f80, + f128 => sin_f128, + else => comptime unreachable, }; try expect(math.isPositiveZero(f(0.0))); @@ -214,13 +227,13 @@ fn testSinSpecial(comptime T: type) !void { test "sin32.normal" { const epsilon = math.floatEps(f32); - try expectApproxEqAbs(@as(f32, 0.0), sinf(0.0), epsilon); - try expectApproxEqAbs(@as(f32, 0.19866933), sinf(0.2), epsilon); - try expectApproxEqAbs(@as(f32, 0.77851737), sinf(0.8923), epsilon); - try expectApproxEqAbs(@as(f32, 0.997495), sinf(1.5), epsilon); - try expectApproxEqAbs(@as(f32, -0.997495), sinf(-1.5), epsilon); - try expectApproxEqAbs(@as(f32, -0.24654257), sinf(37.45), epsilon); - try expectApproxEqAbs(@as(f32, 0.9161657), sinf(89.123), epsilon); + try expectApproxEqAbs(@as(f32, 0.0), sin_f32(0.0), epsilon); + try expectApproxEqAbs(@as(f32, 0.19866933), sin_f32(0.2), epsilon); + try expectApproxEqAbs(@as(f32, 0.77851737), sin_f32(0.8923), epsilon); + try expectApproxEqAbs(@as(f32, 0.997495), sin_f32(1.5), epsilon); + try expectApproxEqAbs(@as(f32, -0.997495), sin_f32(-1.5), epsilon); + try expectApproxEqAbs(@as(f32, -0.24654257), sin_f32(37.45), epsilon); + try expectApproxEqAbs(@as(f32, 0.9161657), sin_f32(89.123), epsilon); } test "sin32.special" { @@ -229,13 +242,13 @@ test "sin32.special" { test "sin64.normal" { const epsilon = math.floatEps(f64); - try expectApproxEqAbs(@as(f64, 0.0), sin(0.0), epsilon); - try expectApproxEqAbs(@as(f64, 0.19866933079506122), sin(0.2), epsilon); - try expectApproxEqAbs(@as(f64, 0.7785173385577349), sin(0.8923), epsilon); - try expectApproxEqAbs(@as(f64, 0.9974949866040544), sin(1.5), epsilon); - try expectApproxEqAbs(@as(f64, -0.9974949866040544), sin(-1.5), epsilon); - try expectApproxEqAbs(@as(f64, -0.24654331551411082), sin(37.45), epsilon); - try expectApproxEqAbs(@as(f64, 0.9161652766622714), sin(89.123), epsilon); + try expectApproxEqAbs(@as(f64, 0.0), sin_f64(0.0), epsilon); + try expectApproxEqAbs(@as(f64, 0.19866933079506122), sin_f64(0.2), epsilon); + try expectApproxEqAbs(@as(f64, 0.7785173385577349), sin_f64(0.8923), epsilon); + try expectApproxEqAbs(@as(f64, 0.9974949866040544), sin_f64(1.5), epsilon); + try expectApproxEqAbs(@as(f64, -0.9974949866040544), sin_f64(-1.5), epsilon); + try expectApproxEqAbs(@as(f64, -0.24654331551411082), sin_f64(37.45), epsilon); + try expectApproxEqAbs(@as(f64, 0.9161652766622714), sin_f64(89.123), epsilon); } test "sin64.special" { @@ -244,13 +257,13 @@ test "sin64.special" { test "sin80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 0.0), sinx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), sinx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), sinx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), sinx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), sinx(-1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.24654331551411356504), sinx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 0.91616527666226951006), sinx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 0.0), sin_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), sin_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), sin_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), sin_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), sin_f80(-1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.24654331551411356504), sin_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 0.91616527666226951006), sin_f80(89.123), epsilon); } test "sin80.special" { @@ -259,13 +272,13 @@ test "sin80.special" { test "sin128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 0.0), sinq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), sinq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), sinq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), sinq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), sinq(-1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), sinq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), sinq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 0.0), sin_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), sin_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), sin_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), sin_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), sin_f128(-1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), sin_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), sin_f128(89.123), epsilon); } test "sin128.special" { @@ -274,10 +287,10 @@ test "sin128.special" { test "sin32 #9901" { const float: f32 = @bitCast(@as(u32, 0b11100011111111110000000000000000)); - _ = sinf(float); + _ = sin_f32(float); } test "sin64 #9901" { const float: f64 = @bitCast(@as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001)); - _ = sin(float); + _ = sin_f64(float); } diff --git a/lib/compiler_rt/sincos.zig b/lib/compiler_rt/sincos.zig index 24bb751e76e7e93d32b05a4a801dec6d5d474709..d43f55b623954f602edf850b75d409931b1aaee6 100644 --- a/lib/compiler_rt/sincos.zig +++ b/lib/compiler_rt/sincos.zig @@ -18,23 +18,27 @@ comptime { symbol(&sincosf, "sincosf"); symbol(&sincos, "sincos"); symbol(&sincosx, "__sincosx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sincosq, "sincosf128"); - } - symbol(&sincosq, "sincosq"); + symbol(&sincosq, "sincosf128"); symbol(&sincosl, "sincosl"); } -pub fn sincosh(x: f16, r_sin: *f16, r_cos: *f16) callconv(.c) void { +fn sincosh(x: compiler_rt.f16.Abi, r_sin: *compiler_rt.f16.Abi, r_cos: *compiler_rt.f16.Abi) callconv(.c) void { + const s, const c = sincos_f16(compiler_rt.f16.fromAbi(x)); + r_sin.* = compiler_rt.f16.toAbi(s); + r_cos.* = compiler_rt.f16.toAbi(c); +} +pub fn sincos_f16(x: f16) struct { f16, f16 } { // TODO: more efficient implementation - var big_sin: f32 = undefined; - var big_cos: f32 = undefined; - sincosf(x, &big_sin, &big_cos); - r_sin.* = @as(f16, @floatCast(big_sin)); - r_cos.* = @as(f16, @floatCast(big_cos)); + const s, const c = sincos_f32(x); + return .{ @floatCast(s), @floatCast(c) }; } -pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { +fn sincosf(x: compiler_rt.f32.Abi, r_sin: *compiler_rt.f32.Abi, r_cos: *compiler_rt.f32.Abi) callconv(.c) void { + const s, const c = sincos_f32(compiler_rt.f32.fromAbi(x)); + r_sin.* = compiler_rt.f32.toAbi(s); + r_cos.* = compiler_rt.f32.toAbi(c); +} +pub fn sincos_f32(x: f32) struct { f32, f32 } { const sc1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const sc2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 const sc3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 @@ -56,13 +60,9 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { mem.doNotOptimizeAway(x + 0x1p120); } } - r_sin.* = x; - r_cos.* = 1.0; - return; + return .{ x, 1.0 }; } - r_sin.* = trig.sindf(x); - r_cos.* = trig.cosdf(x); - return; + return .{ trig.sindf(x), trig.cosdf(x) }; } // |x| ~<= 5*pi/4 @@ -70,18 +70,16 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { // |x| ~<= 3pi/4 if (ix <= 0x4016cbe3) { if (sign) { - r_sin.* = -trig.cosdf(x + sc1pio2); - r_cos.* = trig.sindf(x + sc1pio2); + return .{ -trig.cosdf(x + sc1pio2), trig.sindf(x + sc1pio2) }; } else { - r_sin.* = trig.cosdf(sc1pio2 - x); - r_cos.* = trig.sindf(sc1pio2 - x); + return .{ trig.cosdf(sc1pio2 - x), trig.sindf(sc1pio2 - x) }; } - return; } // -sin(x+c) is not correct if x+c could be 0: -0 vs +0 - r_sin.* = -trig.sindf(if (sign) x + sc2pio2 else x - sc2pio2); - r_cos.* = -trig.cosdf(if (sign) x + sc2pio2 else x - sc2pio2); - return; + return .{ + -trig.sindf(if (sign) x + sc2pio2 else x - sc2pio2), + -trig.cosdf(if (sign) x + sc2pio2 else x - sc2pio2), + }; } // |x| ~<= 9*pi/4 @@ -89,25 +87,21 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { // |x| ~<= 7*pi/4 if (ix <= 0x40afeddf) { if (sign) { - r_sin.* = trig.cosdf(x + sc3pio2); - r_cos.* = -trig.sindf(x + sc3pio2); + return .{ trig.cosdf(x + sc3pio2), -trig.sindf(x + sc3pio2) }; } else { - r_sin.* = -trig.cosdf(x - sc3pio2); - r_cos.* = trig.sindf(x - sc3pio2); + return .{ -trig.cosdf(x - sc3pio2), trig.sindf(x - sc3pio2) }; } - return; } - r_sin.* = trig.sindf(if (sign) x + sc4pio2 else x - sc4pio2); - r_cos.* = trig.cosdf(if (sign) x + sc4pio2 else x - sc4pio2); - return; + return .{ + trig.sindf(if (sign) x + sc4pio2 else x - sc4pio2), + trig.cosdf(if (sign) x + sc4pio2 else x - sc4pio2), + }; } // sin(Inf or NaN) is NaN if (ix >= 0x7f800000) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } // general argument reduction needed @@ -115,27 +109,20 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { const n = rem_pio2f(x, &y); const s = trig.sindf(y); const c = trig.cosdf(y); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { +fn sincos(x: compiler_rt.f64.Abi, r_sin: *compiler_rt.f64.Abi, r_cos: *compiler_rt.f64.Abi) callconv(.c) void { + const s, const c = sincos_f64(compiler_rt.f64.fromAbi(x)); + r_sin.* = compiler_rt.f64.toAbi(s); + r_cos.* = compiler_rt.f64.toAbi(c); +} +pub fn sincos_f64(x: f64) struct { f64, f64 } { const ix = @as(u32, @truncate(@as(u64, @bitCast(x)) >> 32)) & 0x7fffffff; // |x| ~< pi/4 @@ -150,21 +137,15 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { mem.doNotOptimizeAway(x + 0x1p120); } } - r_sin.* = x; - r_cos.* = 1.0; - return; + return .{ x, 1.0 }; } - r_sin.* = trig.sin(x, 0.0, 0); - r_cos.* = trig.cos(x, 0.0); - return; + return .{ trig.sin(x, 0.0, 0), trig.cos(x, 0.0) }; } // sincos(Inf or NaN) is NaN if (ix >= 0x7ff00000) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } // argument reduction needed @@ -172,33 +153,24 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { const n = rem_pio2(x, &y); const s = trig.sin(y[0], y[1], 1); const c = trig.cos(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincosx(x: f80, r_sin: *f80, r_cos: *f80) callconv(.c) void { +fn sincosx(x: compiler_rt.f80.Abi, r_sin: *compiler_rt.f80.Abi, r_cos: *compiler_rt.f80.Abi) callconv(.c) void { + const s, const c = sincos_f80(compiler_rt.f80.fromAbi(x)); + r_sin.* = compiler_rt.f80.toAbi(s); + r_cos.* = compiler_rt.f80.toAbi(c); +} +pub fn sincos_f80(x: f80) struct { f80, f80 } { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } if (@abs(x) < trig.pi_4) { @@ -207,47 +179,34 @@ pub fn sincosx(x: f80, r_sin: *f80, r_cos: *f80) callconv(.c) void { if (compiler_rt.want_float_exceptions and se == 0) { mem.doNotOptimizeAway(x * 0x1p-120); } - r_sin.* = x; // raise inexact if x!=0 - r_cos.* = 1.0 + x; - return; + return .{ x, 1.0 + x }; } - r_sin.* = trig.sinx(x, 0.0, 0); - r_cos.* = trig.cosx(x, 0.0); - return; + return .{ trig.sinx(x, 0.0, 0), trig.cosx(x, 0.0) }; } var y: [2]f80 = undefined; const n = rem_pio2l(f80, x, &y); const s = trig.sinx(y[0], y[1], 1); const c = trig.cosx(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.c) void { +fn sincosq(x: compiler_rt.f128.Abi, r_sin: *compiler_rt.f128.Abi, r_cos: *compiler_rt.f128.Abi) callconv(.c) void { + const s, const c = sincos_f128(compiler_rt.f128.fromAbi(x)); + r_sin.* = compiler_rt.f128.toAbi(s); + r_cos.* = compiler_rt.f128.toAbi(c); +} +pub fn sincos_f128(x: f128) struct { f128, f128 } { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } if (@abs(x) < trig.pi_4) { @@ -256,78 +215,63 @@ pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.c) void { if (compiler_rt.want_float_exceptions and se == 0) { mem.doNotOptimizeAway(x * 0x1p-120); } - r_sin.* = x; // raise inexact if x!=0 - r_cos.* = 1.0 + x; - return; + return .{ x, 1.0 + x }; } - r_sin.* = trig.sinq(x, 0.0, 0); - r_cos.* = trig.cosq(x, 0.0); - return; + return .{ trig.sinq(x, 0.0, 0), trig.cosq(x, 0.0) }; } var y: [2]f128 = undefined; const n = rem_pio2l(f128, x, &y); const s = trig.sinq(y[0], y[1], 1); const c = trig.cosq(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } pub fn sincosl(x: c_longdouble, r_sin: *c_longdouble, r_cos: *c_longdouble) callconv(.c) void { - switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sincos(x, r_sin, r_cos), - 80 => return sincosx(x, r_sin, r_cos), - 128 => return sincosq(x, r_sin, r_cos), - else => @compileError("unreachable"), - } + r_sin.*, r_cos.* = switch (@typeInfo(c_longdouble).float.bits) { + 64 => sincos_f64(x), + 80 => sincos_f80(x), + 128 => sincos_f128(x), + else => comptime unreachable, + }; } fn testSincosSpecial(comptime T: type) !void { const f = switch (T) { - f32 => sincosf, - f64 => sincos, - f80 => sincosx, - f128 => sincosq, + f16 => sincos_f16, + f32 => sincos_f32, + f64 => sincos_f64, + f80 => sincos_f80, + f128 => sincos_f128, else => @compileError("unimplemented"), }; var s: T = undefined; var c: T = undefined; - f(0.0, &s, &c); + s, c = f(0.0); try expect(math.isPositiveZero(s)); try expect(c == 1.0); - f(-0.0, &s, &c); + s, c = f(-0.0); try expect(math.isNegativeZero(s)); try expect(c == 1.0); - f(math.inf(T), &s, &c); + s, c = f(math.inf(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); - f(-math.inf(T), &s, &c); + s, c = f(-math.inf(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); - f(math.nan(T), &s, &c); + s, c = f(math.nan(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); } @@ -337,31 +281,31 @@ test "sincos32.normal" { var s: f32 = undefined; var c: f32 = undefined; - sincosf(0.0, &s, &c); + s, c = sincos_f32(0.0); try expectApproxEqAbs(@as(f32, 0.0), s, epsilon); try expectApproxEqAbs(@as(f32, 1.0), c, epsilon); - sincosf(0.2, &s, &c); + s, c = sincos_f32(0.2); try expectApproxEqAbs(@as(f32, 0.19866933), s, epsilon); try expectApproxEqAbs(@as(f32, 0.9800666), c, epsilon); - sincosf(0.8923, &s, &c); + s, c = sincos_f32(0.8923); try expectApproxEqAbs(@as(f32, 0.77851737), s, epsilon); try expectApproxEqAbs(@as(f32, 0.6276231), c, epsilon); - sincosf(1.5, &s, &c); + s, c = sincos_f32(1.5); try expectApproxEqAbs(@as(f32, 0.997495), s, epsilon); try expectApproxEqAbs(@as(f32, 0.0707372), c, epsilon); - sincosf(-1.5, &s, &c); + s, c = sincos_f32(-1.5); try expectApproxEqAbs(@as(f32, -0.997495), s, epsilon); try expectApproxEqAbs(@as(f32, 0.0707372), c, epsilon); - sincosf(37.45, &s, &c); + s, c = sincos_f32(37.45); try expectApproxEqAbs(@as(f32, -0.24654257), s, epsilon); try expectApproxEqAbs(@as(f32, 0.96913195), c, epsilon); - sincosf(89.123, &s, &c); + s, c = sincos_f32(89.123); try expectApproxEqAbs(@as(f32, 0.9161657), s, epsilon); try expectApproxEqAbs(@as(f32, 0.40079966), c, epsilon); } @@ -375,31 +319,31 @@ test "sincos64.normal" { var s: f64 = undefined; var c: f64 = undefined; - sincos(0.0, &s, &c); + s, c = sincos_f64(0.0); try expectApproxEqAbs(@as(f64, 0.0), s, epsilon); try expectApproxEqAbs(@as(f64, 1.0), c, epsilon); - sincos(0.2, &s, &c); + s, c = sincos_f64(0.2); try expectApproxEqAbs(@as(f64, 0.19866933079506122), s, epsilon); try expectApproxEqAbs(@as(f64, 0.9800665778412416), c, epsilon); - sincos(0.8923, &s, &c); + s, c = sincos_f64(0.8923); try expectApproxEqAbs(@as(f64, 0.7785173385577349), s, epsilon); try expectApproxEqAbs(@as(f64, 0.6276230983360804), c, epsilon); - sincos(1.5, &s, &c); + s, c = sincos_f64(1.5); try expectApproxEqAbs(@as(f64, 0.9974949866040544), s, epsilon); try expectApproxEqAbs(@as(f64, 0.0707372016677029), c, epsilon); - sincos(-1.5, &s, &c); + s, c = sincos_f64(-1.5); try expectApproxEqAbs(@as(f64, -0.9974949866040544), s, epsilon); try expectApproxEqAbs(@as(f64, 0.0707372016677029), c, epsilon); - sincos(37.45, &s, &c); + s, c = sincos_f64(37.45); try expectApproxEqAbs(@as(f64, -0.24654331551411082), s, epsilon); try expectApproxEqAbs(@as(f64, 0.9691317730707778), c, epsilon); - sincos(89.123, &s, &c); + s, c = sincos_f64(89.123); try expectApproxEqAbs(@as(f64, 0.9161652766622714), s, epsilon); try expectApproxEqAbs(@as(f64, 0.4008006809354791), c, epsilon); } @@ -413,31 +357,31 @@ test "sincos80.normal" { var s: f80 = undefined; var c: f80 = undefined; - sincosx(0.0, &s, &c); + s, c = sincos_f80(0.0); try expectApproxEqAbs(@as(f80, 0.0), s, epsilon); try expectApproxEqAbs(@as(f80, 1.0), c, epsilon); - sincosx(0.2, &s, &c); + s, c = sincos_f80(0.2); try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), s, epsilon); try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), c, epsilon); - sincosx(0.8923, &s, &c); + s, c = sincos_f80(0.8923); try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), s, epsilon); try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), c, epsilon); - sincosx(1.5, &s, &c); + s, c = sincos_f80(1.5); try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), c, epsilon); - sincosx(-1.5, &s, &c); + s, c = sincos_f80(-1.5); try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), c, epsilon); - sincosx(37.45, &s, &c); + s, c = sincos_f80(37.45); try expectApproxEqAbs(@as(f80, -0.24654331551411356504), s, epsilon); try expectApproxEqAbs(@as(f80, 0.9691317730707771246), c, epsilon); - sincosx(89.123, &s, &c); + s, c = sincos_f80(89.123); try expectApproxEqAbs(@as(f80, 0.91616527666226951006), s, epsilon); try expectApproxEqAbs(@as(f80, 0.4008006809354834001), c, epsilon); } @@ -451,31 +395,31 @@ test "sincos128.normal" { var s: f128 = undefined; var c: f128 = undefined; - sincosq(0.0, &s, &c); + s, c = sincos_f128(0.0); try expectApproxEqAbs(@as(f128, 0.0), s, epsilon); try expectApproxEqAbs(@as(f128, 1.0), c, epsilon); - sincosq(0.2, &s, &c); + s, c = sincos_f128(0.2); try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), s, epsilon); try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), c, epsilon); - sincosq(0.8923, &s, &c); + s, c = sincos_f128(0.8923); try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), s, epsilon); try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), c, epsilon); - sincosq(1.5, &s, &c); + s, c = sincos_f128(1.5); try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), c, epsilon); - sincosq(-1.5, &s, &c); + s, c = sincos_f128(-1.5); try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), c, epsilon); - sincosq(37.45, &s, &c); + s, c = sincos_f128(37.45); try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), s, epsilon); try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), c, epsilon); - sincosq(89.123, &s, &c); + s, c = sincos_f128(89.123); try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), s, epsilon); try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), c, epsilon); } diff --git a/lib/compiler_rt/sqrt.zig b/lib/compiler_rt/sqrt.zig index 739285af0eaa66af2cf6ed31a3dcc142a708b590..a37fe429c1458153dded08805982d118dedb8ebb 100644 --- a/lib/compiler_rt/sqrt.zig +++ b/lib/compiler_rt/sqrt.zig @@ -17,18 +17,19 @@ comptime { symbol(&sqrtf, "sqrtf"); symbol(&sqrt, "sqrt"); symbol(&__sqrtx, "__sqrtx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sqrtq, "sqrtf128"); - } else if (compiler_rt.want_sparc64_abi) { + symbol(&sqrtq, "sqrtf128"); + if (compiler_rt.want_sparc64_abi) { symbol(&_Qp_sqrt, "_Qp_sqrt"); } else if (compiler_rt.want_sparc32_abi) { symbol(&sqrtq, "_Q_sqrt"); } - symbol(&sqrtq, "sqrtq"); symbol(&sqrtl, "sqrtl"); } -pub fn __sqrth(x: f16) callconv(.c) f16 { +fn __sqrth(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sqrt_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn sqrt_f16(x: f16) f16 { var ix: u16 = @bitCast(x); var top = ix >> 10; @@ -93,7 +94,10 @@ pub fn __sqrth(x: f16) callconv(.c) f16 { return y; } -pub fn sqrtf(x: f32) callconv(.c) f32 { +fn sqrtf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sqrt_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn sqrt_f32(x: f32) f32 { var ix: u32 = @bitCast(x); if (ix < @as(u32, @bitCast(@as(f32, 0x1p-126))) or @as(u32, @bitCast(std.math.inf(f32))) <= ix) { @@ -147,7 +151,10 @@ pub fn sqrtf(x: f32) callconv(.c) f32 { return y + t; } -pub fn sqrt(x: f64) callconv(.c) f64 { +fn sqrt(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sqrt_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn sqrt_f64(x: f64) f64 { var ix: u64 = @bitCast(x); var top = ix >> 52; @@ -284,7 +291,10 @@ pub fn sqrt(x: f64) callconv(.c) f64 { return y; } -pub fn __sqrtx(x: f80) callconv(.c) f80 { +fn __sqrtx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sqrt_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn sqrt_f80(x: f80) f80 { var ix: u80 = @bitCast(x); var top = ix >> 64; @@ -381,7 +391,10 @@ pub fn __sqrtx(x: f80) callconv(.c) f80 { return y; } -pub fn sqrtq(x: f128) callconv(.c) f128 { +fn sqrtq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sqrt_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn sqrt_f128(x: f128) f128 { var ix: u128 = @bitCast(x); var top = ix >> 112; @@ -483,10 +496,10 @@ fn _Qp_sqrt(c: *f128, a: *f128) callconv(.c) void { pub fn sqrtl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sqrt(x), - 80 => return __sqrtx(x), - 128 => return sqrtq(x), - else => @compileError("unreachable"), + 64 => return sqrt_f64(x), + 80 => return sqrt_f80(x), + 128 => return sqrt_f128(x), + else => comptime unreachable, } } @@ -545,187 +558,187 @@ inline fn mul80_tail(a: u80, b: u80) u80 { return alo * blo +% ((ahi * blo) << 40) +% ((alo * bhi) << 40); } -test "__sqrth" { +test "sqrt_f16" { // sqrt(±0) is ±0 - try std.testing.expectEqual(__sqrth(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(__sqrth(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f16(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f16(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(__sqrth(0x1.FFCp15), 0x1.FFCp7); + try std.testing.expectEqual(sqrt_f16(0x1.FFCp15), 0x1.FFCp7); // sqrt(4)=2 - try std.testing.expectEqual(__sqrth(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f16(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(__sqrth(0x1p0), 0x1p0); - try std.testing.expectEqual(__sqrth(0x1.004p0), 0x1p0); - try std.testing.expectEqual(__sqrth(0x1.FF8p-1), 0x1.FFCp-1); + try std.testing.expectEqual(sqrt_f16(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f16(0x1.004p0), 0x1p0); + try std.testing.expectEqual(sqrt_f16(0x1.FF8p-1), 0x1.FFCp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(__sqrth(0x1p-14), 0x1p-7); + try std.testing.expectEqual(sqrt_f16(0x1p-14), 0x1p-7); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(__sqrth(0x0.004p-14), 0x1p-12); + try std.testing.expectEqual(sqrt_f16(0x0.004p-14), 0x1p-12); // sqrt(inf) is inf - try std.testing.expect(math.isInf(__sqrth(math.inf(f16)))); + try std.testing.expect(math.isInf(sqrt_f16(math.inf(f16)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(__sqrth(math.nan(f16)))); + try std.testing.expect(math.isNan(sqrt_f16(math.nan(f16)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(__sqrth(-0x1p-14))); - try std.testing.expect(math.isNan(__sqrth(-0x1p+0))); - try std.testing.expect(math.isNan(__sqrth(-math.inf(f16)))); + try std.testing.expect(math.isNan(sqrt_f16(-0x1p-14))); + try std.testing.expect(math.isNan(sqrt_f16(-0x1p+0))); + try std.testing.expect(math.isNan(sqrt_f16(-math.inf(f16)))); // random arguments - try std.testing.expectEqual(__sqrth(0x1.1p14), 0x1.08p7); - try std.testing.expectEqual(__sqrth(0x1.C9p-12), 0x1.56p-6); - try std.testing.expectEqual(__sqrth(0x1.CE8p-7), 0x1.E68p-4); - try std.testing.expectEqual(__sqrth(0x1.134p-7), 0x1.778p-4); - try std.testing.expectEqual(__sqrth(0x1.E9Cp-10), 0x1.62p-5); - try std.testing.expectEqual(__sqrth(0x1.3Dp9), 0x1.92Cp4); - try std.testing.expectEqual(__sqrth(0x1.AA4p8), 0x1.4A4p4); - try std.testing.expectEqual(__sqrth(0x1.8A8p4), 0x1.3DCp2); - try std.testing.expectEqual(__sqrth(0x1.8Fp-7), 0x1.C4p-4); - try std.testing.expectEqual(__sqrth(0x1.584p-11), 0x1.A3Cp-6); + try std.testing.expectEqual(sqrt_f16(0x1.1p14), 0x1.08p7); + try std.testing.expectEqual(sqrt_f16(0x1.C9p-12), 0x1.56p-6); + try std.testing.expectEqual(sqrt_f16(0x1.CE8p-7), 0x1.E68p-4); + try std.testing.expectEqual(sqrt_f16(0x1.134p-7), 0x1.778p-4); + try std.testing.expectEqual(sqrt_f16(0x1.E9Cp-10), 0x1.62p-5); + try std.testing.expectEqual(sqrt_f16(0x1.3Dp9), 0x1.92Cp4); + try std.testing.expectEqual(sqrt_f16(0x1.AA4p8), 0x1.4A4p4); + try std.testing.expectEqual(sqrt_f16(0x1.8A8p4), 0x1.3DCp2); + try std.testing.expectEqual(sqrt_f16(0x1.8Fp-7), 0x1.C4p-4); + try std.testing.expectEqual(sqrt_f16(0x1.584p-11), 0x1.A3Cp-6); } -test "sqrtf" { +test "sqrt_f32" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrtf(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrtf(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f32(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f32(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrtf(0x1.FFFFFEp127), 0x1.FFFFFEp63); + try std.testing.expectEqual(sqrt_f32(0x1.FFFFFEp127), 0x1.FFFFFEp63); // sqrt(4)=2 - try std.testing.expectEqual(sqrtf(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f32(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrtf(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrtf(0x1.000002p0), 0x1p0); - try std.testing.expectEqual(sqrtf(0x1.FFFFFEp-1), 0x1.FFFFFEp-1); + try std.testing.expectEqual(sqrt_f32(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f32(0x1.000002p0), 0x1p0); + try std.testing.expectEqual(sqrt_f32(0x1.FFFFFEp-1), 0x1.FFFFFEp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrtf(0x1p-126), 0x1p-63); + try std.testing.expectEqual(sqrt_f32(0x1p-126), 0x1p-63); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrtf(0x0.000002p-126), 0x1.6a09e6p-75); + try std.testing.expectEqual(sqrt_f32(0x0.000002p-126), 0x1.6a09e6p-75); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrtf(math.inf(f32)))); + try std.testing.expect(math.isInf(sqrt_f32(math.inf(f32)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrtf(math.nan(f32)))); + try std.testing.expect(math.isNan(sqrt_f32(math.nan(f32)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrtf(-0x1p-149))); - try std.testing.expect(math.isNan(sqrtf(-0x1p0))); - try std.testing.expect(math.isNan(sqrtf(-math.inf(f32)))); + try std.testing.expect(math.isNan(sqrt_f32(-0x1p-149))); + try std.testing.expect(math.isNan(sqrt_f32(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f32(-math.inf(f32)))); // random arguments - try std.testing.expectEqual(sqrtf(0x1.4DD57Ep77), 0x1.9D6DA8p38); - try std.testing.expectEqual(sqrtf(0x1.871848p102), 0x1.3C6AFAp51); - try std.testing.expectEqual(sqrtf(0x1.A1D748p-112), 0x1.470EFCp-56); - try std.testing.expectEqual(sqrtf(0x1.E626C2p18), 0x1.60C80Ep9); - try std.testing.expectEqual(sqrtf(0x1.E80E66p-29), 0x1.F3E282p-15); - try std.testing.expectEqual(sqrtf(0x1.B47204p89), 0x1.D8B732p44); - try std.testing.expectEqual(sqrtf(0x1.77F45p15), 0x1.B6BC3Ap7); - try std.testing.expectEqual(sqrtf(0x1.AD5F5p-48), 0x1.4B8A72p-24); - try std.testing.expectEqual(sqrtf(0x1.91A39p-76), 0x1.40A7A8p-38); - try std.testing.expectEqual(sqrtf(0x1.DAE088p79), 0x1.ED16DCp39); + try std.testing.expectEqual(sqrt_f32(0x1.4DD57Ep77), 0x1.9D6DA8p38); + try std.testing.expectEqual(sqrt_f32(0x1.871848p102), 0x1.3C6AFAp51); + try std.testing.expectEqual(sqrt_f32(0x1.A1D748p-112), 0x1.470EFCp-56); + try std.testing.expectEqual(sqrt_f32(0x1.E626C2p18), 0x1.60C80Ep9); + try std.testing.expectEqual(sqrt_f32(0x1.E80E66p-29), 0x1.F3E282p-15); + try std.testing.expectEqual(sqrt_f32(0x1.B47204p89), 0x1.D8B732p44); + try std.testing.expectEqual(sqrt_f32(0x1.77F45p15), 0x1.B6BC3Ap7); + try std.testing.expectEqual(sqrt_f32(0x1.AD5F5p-48), 0x1.4B8A72p-24); + try std.testing.expectEqual(sqrt_f32(0x1.91A39p-76), 0x1.40A7A8p-38); + try std.testing.expectEqual(sqrt_f32(0x1.DAE088p79), 0x1.ED16DCp39); } -test "sqrt" { +test "sqrt_f64" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrt(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrt(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f64(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f64(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrt(math.floatMax(f64)), 0x1.FFFFFFFFFFFFFp511); + try std.testing.expectEqual(sqrt_f64(math.floatMax(f64)), 0x1.FFFFFFFFFFFFFp511); // sqrt(4)=2 - try std.testing.expectEqual(sqrt(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f64(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrt(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrt(0x1p0 + math.floatEps(f64)), 0x1p0); - try std.testing.expectEqual(sqrt(0x1p0 - math.floatEps(f64)), 0x1.FFFFFFFFFFFFFp-1); + try std.testing.expectEqual(sqrt_f64(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f64(0x1p0 + math.floatEps(f64)), 0x1p0); + try std.testing.expectEqual(sqrt_f64(0x1p0 - math.floatEps(f64)), 0x1.FFFFFFFFFFFFFp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrt(math.floatMin(f64)), 0x1p-511); + try std.testing.expectEqual(sqrt_f64(math.floatMin(f64)), 0x1p-511); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrt(math.floatTrueMin(f64)), 0x1p-537); + try std.testing.expectEqual(sqrt_f64(math.floatTrueMin(f64)), 0x1p-537); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrt(math.inf(f64)))); + try std.testing.expect(math.isInf(sqrt_f64(math.inf(f64)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrt(math.nan(f64)))); + try std.testing.expect(math.isNan(sqrt_f64(math.nan(f64)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrt(-0x1p-1074))); - try std.testing.expect(math.isNan(sqrt(-0x1p0))); - try std.testing.expect(math.isNan(sqrt(-math.inf(f64)))); + try std.testing.expect(math.isNan(sqrt_f64(-0x1p-1074))); + try std.testing.expect(math.isNan(sqrt_f64(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f64(-math.inf(f64)))); // random arguments - try std.testing.expectEqual(sqrt(0x1.27D3510D4789Bp471), 0x1.852E97E58CFB7p235); - try std.testing.expectEqual(sqrt(0x1.8C4FCD5A07846p791), 0x1.C27504E56D938p395); - try std.testing.expectEqual(sqrt(0x1.B1B69324F96E7p-137), 0x1.D73BD0414D8BFp-69); - try std.testing.expectEqual(sqrt(0x1.1CBD179A811FEp278), 0x1.0DFCB9A114A61p139); - try std.testing.expectEqual(sqrt(0x1.1D0C7EFB04A56p917), 0x1.7E0708A25DDCDp458); - try std.testing.expectEqual(sqrt(0x1.21B355DA8C94Bp-249), 0x1.8121CBE2608E3p-125); - try std.testing.expectEqual(sqrt(0x1.63024D4C5E987p487), 0x1.AA56AEA589DCDp243); - try std.testing.expectEqual(sqrt(0x1.45AC3BE941F6Ep339), 0x1.9857F3F453E2Dp169); - try std.testing.expectEqual(sqrt(0x1.3B719C733AA24p267), 0x1.91E12E3AC8F71p133); - try std.testing.expectEqual(sqrt(0x1.0B150433A2275p357), 0x1.71CAB87F8277Cp178); + try std.testing.expectEqual(sqrt_f64(0x1.27D3510D4789Bp471), 0x1.852E97E58CFB7p235); + try std.testing.expectEqual(sqrt_f64(0x1.8C4FCD5A07846p791), 0x1.C27504E56D938p395); + try std.testing.expectEqual(sqrt_f64(0x1.B1B69324F96E7p-137), 0x1.D73BD0414D8BFp-69); + try std.testing.expectEqual(sqrt_f64(0x1.1CBD179A811FEp278), 0x1.0DFCB9A114A61p139); + try std.testing.expectEqual(sqrt_f64(0x1.1D0C7EFB04A56p917), 0x1.7E0708A25DDCDp458); + try std.testing.expectEqual(sqrt_f64(0x1.21B355DA8C94Bp-249), 0x1.8121CBE2608E3p-125); + try std.testing.expectEqual(sqrt_f64(0x1.63024D4C5E987p487), 0x1.AA56AEA589DCDp243); + try std.testing.expectEqual(sqrt_f64(0x1.45AC3BE941F6Ep339), 0x1.9857F3F453E2Dp169); + try std.testing.expectEqual(sqrt_f64(0x1.3B719C733AA24p267), 0x1.91E12E3AC8F71p133); + try std.testing.expectEqual(sqrt_f64(0x1.0B150433A2275p357), 0x1.71CAB87F8277Cp178); } test "__sqrtx" { // sqrt(±0) is ±0 - try std.testing.expectEqual(__sqrtx(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(__sqrtx(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f80(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f80(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(__sqrtx(math.floatMax(f80)), 0x1.FFFFFFFFFFFFFFFEp8191); + try std.testing.expectEqual(sqrt_f80(math.floatMax(f80)), 0x1.FFFFFFFFFFFFFFFEp8191); // sqrt(4)=2 - try std.testing.expectEqual(__sqrtx(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f80(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(__sqrtx(0x1p0), 0x1p0); - try std.testing.expectEqual(__sqrtx(0x1p0 + math.floatEps(f80)), 0x1p0); - try std.testing.expectEqual(__sqrtx(0x1p0 - math.floatEps(f80)), 0x1.FFFFFFFFFFFFFFFEp-1); + try std.testing.expectEqual(sqrt_f80(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f80(0x1p0 + math.floatEps(f80)), 0x1p0); + try std.testing.expectEqual(sqrt_f80(0x1p0 - math.floatEps(f80)), 0x1.FFFFFFFFFFFFFFFEp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(__sqrtx(math.floatMin(f80)), 0x1p-8191); + try std.testing.expectEqual(sqrt_f80(math.floatMin(f80)), 0x1p-8191); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(__sqrtx(math.floatTrueMin(f80)), 0x1.6A09E667F3BCC908p-8223); + try std.testing.expectEqual(sqrt_f80(math.floatTrueMin(f80)), 0x1.6A09E667F3BCC908p-8223); // sqrt(inf) is inf - try std.testing.expect(math.isInf(__sqrtx(math.inf(f80)))); + try std.testing.expect(math.isInf(sqrt_f80(math.inf(f80)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(__sqrtx(math.nan(f80)))); + try std.testing.expect(math.isNan(sqrt_f80(math.nan(f80)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(__sqrtx(-0x1p-16442))); - try std.testing.expect(math.isNan(__sqrtx(-0x1p0))); - try std.testing.expect(math.isNan(__sqrtx(-math.inf(f80)))); + try std.testing.expect(math.isNan(sqrt_f80(-0x1p-16442))); + try std.testing.expect(math.isNan(sqrt_f80(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f80(-math.inf(f80)))); // random arguments - try std.testing.expectEqual(__sqrtx(0x1.087F3953486918A4p15482), 0x1.0436BBE03D02F32p7741); - try std.testing.expectEqual(__sqrtx(0x1.530CF9E2AE84D8Fp-6330), 0x1.269CFEF51933BE58p-3165); - try std.testing.expectEqual(__sqrtx(0x1.3F971515EADD574Ap5713), 0x1.9483232AB780B006p2856); - try std.testing.expectEqual(__sqrtx(0x1.4CC0DC7379222954p864), 0x1.23DD4D0A4758C2Cp432); - try std.testing.expectEqual(__sqrtx(0x1.920E5649559A839Ep-3181), 0x1.C5B5BC0F98DD83D2p-1591); - try std.testing.expectEqual(__sqrtx(0x1.2E59726F87CD1746p-629), 0x1.8973327E95CB350Cp-315); - try std.testing.expectEqual(__sqrtx(0x1.D3A16391F57B4D64p-9034), 0x1.59FF08B7DEEF5DB2p-4517); - try std.testing.expectEqual(__sqrtx(0x1.E7053D8DAA49BCEEp-11411), 0x1.F35AA3EA5E18E344p-5706); - try std.testing.expectEqual(__sqrtx(0x1.797ED0B05DD4A984p7521), 0x1.B7A22E40C6A7867Ap3760); - try std.testing.expectEqual(__sqrtx(0x1.FC50806445C7226Ap15371), 0x1.FE2766142653F5BEp7685); + try std.testing.expectEqual(sqrt_f80(0x1.087F3953486918A4p15482), 0x1.0436BBE03D02F32p7741); + try std.testing.expectEqual(sqrt_f80(0x1.530CF9E2AE84D8Fp-6330), 0x1.269CFEF51933BE58p-3165); + try std.testing.expectEqual(sqrt_f80(0x1.3F971515EADD574Ap5713), 0x1.9483232AB780B006p2856); + try std.testing.expectEqual(sqrt_f80(0x1.4CC0DC7379222954p864), 0x1.23DD4D0A4758C2Cp432); + try std.testing.expectEqual(sqrt_f80(0x1.920E5649559A839Ep-3181), 0x1.C5B5BC0F98DD83D2p-1591); + try std.testing.expectEqual(sqrt_f80(0x1.2E59726F87CD1746p-629), 0x1.8973327E95CB350Cp-315); + try std.testing.expectEqual(sqrt_f80(0x1.D3A16391F57B4D64p-9034), 0x1.59FF08B7DEEF5DB2p-4517); + try std.testing.expectEqual(sqrt_f80(0x1.E7053D8DAA49BCEEp-11411), 0x1.F35AA3EA5E18E344p-5706); + try std.testing.expectEqual(sqrt_f80(0x1.797ED0B05DD4A984p7521), 0x1.B7A22E40C6A7867Ap3760); + try std.testing.expectEqual(sqrt_f80(0x1.FC50806445C7226Ap15371), 0x1.FE2766142653F5BEp7685); } -test "sqrtq" { +test "sqrt_f128" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrtq(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrtq(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f128(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f128(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrtq(math.floatMax(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp8191); + try std.testing.expectEqual(sqrt_f128(math.floatMax(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp8191); // sqrt(4)=2 - try std.testing.expectEqual(sqrtq(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f128(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrtq(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrtq(0x1p0 + math.floatEps(f128)), 0x1p0); - try std.testing.expectEqual(sqrtq(0x1p0 - math.floatEps(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-1); + try std.testing.expectEqual(sqrt_f128(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f128(0x1p0 + math.floatEps(f128)), 0x1p0); + try std.testing.expectEqual(sqrt_f128(0x1p0 - math.floatEps(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrtq(math.floatMin(f128)), 0x1p-8191); + try std.testing.expectEqual(sqrt_f128(math.floatMin(f128)), 0x1p-8191); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrtq(math.floatTrueMin(f128)), 0x1p-8247); + try std.testing.expectEqual(sqrt_f128(math.floatTrueMin(f128)), 0x1p-8247); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrtq(math.inf(f128)))); + try std.testing.expect(math.isInf(sqrt_f128(math.inf(f128)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrtq(math.nan(f128)))); + try std.testing.expect(math.isNan(sqrt_f128(math.nan(f128)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrtq(-0x1p-16442))); - try std.testing.expect(math.isNan(sqrtq(-0x1p0))); - try std.testing.expect(math.isNan(sqrtq(-math.inf(f128)))); + try std.testing.expect(math.isNan(sqrt_f128(-0x1p-16442))); + try std.testing.expect(math.isNan(sqrt_f128(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f128(-math.inf(f128)))); // random arguments - try std.testing.expectEqual(sqrtq(0x1.B6942D29A331751600C9F3AF7E5Fp3363), 0x1.D9DE9AFEF0F2D25586A50CA39D4Dp1681); - try std.testing.expectEqual(sqrtq(0x1.5E65C405F84D471A8070ADD7A42Dp11765), 0x1.A78F7F9452B4D9EC2403C81D9D42p5882); - try std.testing.expectEqual(sqrtq(0x1.B42334D68F8016D8AE6F5E22B044p-5624), 0x1.4E247A7F2FF2A325E9377BB09C8p-2812); - try std.testing.expectEqual(sqrtq(0x1.E61715047F80F2E0B9382B38E06Bp10062), 0x1.60C25D9DFDC0116B78EF5AFDE0E9p5031); - try std.testing.expectEqual(sqrtq(0x1.2ED0B53B494CB55A7B04E653D40Ep-1026), 0x1.166CE78D658D2453D700B04C5748p-513); - try std.testing.expectEqual(sqrtq(0x1.1BA756B9790E78A4E6F0B083AA89p1835), 0x1.7D1767EA3303DB7A46940033988p917); - try std.testing.expectEqual(sqrtq(0x1.5B6C574319C1120335C8E1609704p4512), 0x1.2A3A8A415BB1648C548FBA2A4182p2256); - try std.testing.expectEqual(sqrtq(0x1.FF91E8CDEE1552A2B74E77B602Ep14953), 0x1.FFC8F171267D4FE75CBE7AB4D851p7476); - try std.testing.expectEqual(sqrtq(0x1.9B1837CFC629A1B6B1BB97099E7Dp2892), 0x1.4468511B909EAF8641BD59105A6Bp1446); - try std.testing.expectEqual(sqrtq(0x1.0E2115475E64A92340914E7F7B37p-13951), 0x1.73E536F82F414134012F55BA5368p-6976); + try std.testing.expectEqual(sqrt_f128(0x1.B6942D29A331751600C9F3AF7E5Fp3363), 0x1.D9DE9AFEF0F2D25586A50CA39D4Dp1681); + try std.testing.expectEqual(sqrt_f128(0x1.5E65C405F84D471A8070ADD7A42Dp11765), 0x1.A78F7F9452B4D9EC2403C81D9D42p5882); + try std.testing.expectEqual(sqrt_f128(0x1.B42334D68F8016D8AE6F5E22B044p-5624), 0x1.4E247A7F2FF2A325E9377BB09C8p-2812); + try std.testing.expectEqual(sqrt_f128(0x1.E61715047F80F2E0B9382B38E06Bp10062), 0x1.60C25D9DFDC0116B78EF5AFDE0E9p5031); + try std.testing.expectEqual(sqrt_f128(0x1.2ED0B53B494CB55A7B04E653D40Ep-1026), 0x1.166CE78D658D2453D700B04C5748p-513); + try std.testing.expectEqual(sqrt_f128(0x1.1BA756B9790E78A4E6F0B083AA89p1835), 0x1.7D1767EA3303DB7A46940033988p917); + try std.testing.expectEqual(sqrt_f128(0x1.5B6C574319C1120335C8E1609704p4512), 0x1.2A3A8A415BB1648C548FBA2A4182p2256); + try std.testing.expectEqual(sqrt_f128(0x1.FF91E8CDEE1552A2B74E77B602Ep14953), 0x1.FFC8F171267D4FE75CBE7AB4D851p7476); + try std.testing.expectEqual(sqrt_f128(0x1.9B1837CFC629A1B6B1BB97099E7Dp2892), 0x1.4468511B909EAF8641BD59105A6Bp1446); + try std.testing.expectEqual(sqrt_f128(0x1.0E2115475E64A92340914E7F7B37p-13951), 0x1.73E536F82F414134012F55BA5368p-6976); } diff --git a/lib/compiler_rt/subdf3.zig b/lib/compiler_rt/subdf3.zig deleted file mode 100644 index 4d00a7f03ae71c4f9bf2ffecbcd1123216dff6b6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subdf3.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dsub, "__aeabi_dsub"); - } else { - symbol(&__subdf3, "__subdf3"); - } -} - -fn __subdf3(a: f64, b: f64) callconv(.c) f64 { - return sub(a, b); -} - -fn __aeabi_dsub(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return sub(a, b); -} - -inline fn sub(a: f64, b: f64) f64 { - const neg_b = @as(f64, @bitCast(@as(u64, @bitCast(b)) ^ (@as(u64, 1) << 63))); - return addf3(f64, a, neg_b); -} diff --git a/lib/compiler_rt/subhf3.zig b/lib/compiler_rt/subhf3.zig deleted file mode 100644 index 258401d2957a6d3aafcd0aa02c6de63ca0211952..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subhf3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__subhf3, "__subhf3"); -} - -fn __subhf3(a: f16, b: f16) callconv(.c) f16 { - const neg_b = @as(f16, @bitCast(@as(u16, @bitCast(b)) ^ (@as(u16, 1) << 15))); - return addf3(f16, a, neg_b); -} diff --git a/lib/compiler_rt/subsf3.zig b/lib/compiler_rt/subsf3.zig deleted file mode 100644 index 94d47220166aff38656455d3f50fa2b061df3f61..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subsf3.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fsub, "__aeabi_fsub"); - } else { - symbol(&__subsf3, "__subsf3"); - } -} - -fn __subsf3(a: f32, b: f32) callconv(.c) f32 { - return sub(a, b); -} - -fn __aeabi_fsub(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return sub(a, b); -} - -inline fn sub(a: f32, b: f32) f32 { - const neg_b = @as(f32, @bitCast(@as(u32, @bitCast(b)) ^ (@as(u32, 1) << 31))); - return addf3(f32, a, neg_b); -} diff --git a/lib/compiler_rt/subtf3.zig b/lib/compiler_rt/subtf3.zig deleted file mode 100644 index 46580f1728d70b85c83259dce39cb860e46ac10e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subtf3.zig +++ /dev/null @@ -1,27 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__subtf3, "__subkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_sub, "_Qp_sub"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__subtf3, "_Q_sub"); - } - symbol(&__subtf3, "__subtf3"); -} - -pub fn __subtf3(a: f128, b: f128) callconv(.c) f128 { - return sub(a, b); -} - -fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = sub(a.*, b.*); -} - -inline fn sub(a: f128, b: f128) f128 { - const neg_b = @as(f128, @bitCast(@as(u128, @bitCast(b)) ^ (@as(u128, 1) << 127))); - return addf3(f128, a, neg_b); -} diff --git a/lib/compiler_rt/subvdi3.zig b/lib/compiler_rt/subvdi3.zig index 62bb1b406835c1a72588cd9c1d08705f6663bbd2..2fedc77ee2c07fe42ded5f5da11191a41fc17a0f 100644 --- a/lib/compiler_rt/subvdi3.zig +++ b/lib/compiler_rt/subvdi3.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; const testing = @import("std").testing; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__subvdi3, "__subvdi3"); @@ -9,7 +10,7 @@ pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { const sum = a -% b; // Overflow occurred iff the operands have opposite signs, and the sign of the // sum is the opposite of the lhs sign. - if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); + if (((a ^ b) & (sum ^ a)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/subvsi3.zig b/lib/compiler_rt/subvsi3.zig index 0744585770237d034f35947a927155efe23eaef9..0d2a47e7cbfa8beb25cbeedc1809e549481db97e 100644 --- a/lib/compiler_rt/subvsi3.zig +++ b/lib/compiler_rt/subvsi3.zig @@ -10,7 +10,7 @@ pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { const sum = a -% b; // Overflow occurred iff the operands have opposite signs, and the sign of the // sum is the opposite of the lhs sign. - if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); + if (((a ^ b) & (sum ^ a)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/subxf3.zig b/lib/compiler_rt/subxf3.zig deleted file mode 100644 index 1c2dcd65429596c975937432aae6eaefb89c2f72..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subxf3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const std = @import("std"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__subxf3, "__subxf3"); -} - -fn __subxf3(a: f80, b: f80) callconv(.c) f80 { - var b_rep = std.math.F80.fromFloat(b); - b_rep.exp ^= 0x8000; - const neg_b = b_rep.toFloat(); - return a + neg_b; -} diff --git a/lib/compiler_rt/tan.zig b/lib/compiler_rt/tan.zig index 6cbc3cb098acd1f6a719451d103574b935a8bb2c..4ee4440dd6c5cd7417842de27084cab36ae85907 100644 --- a/lib/compiler_rt/tan.zig +++ b/lib/compiler_rt/tan.zig @@ -21,26 +21,29 @@ const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; const arch = builtin.cpu.arch; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { - symbol(&tanh, "__tanh"); + symbol(&__tanh, "__tanh"); symbol(&tanf, "tanf"); symbol(&tan, "tan"); - symbol(&tanx, "__tanx"); - if (compiler_rt.want_ppc_abi) { - symbol(&tanq, "tanf128"); - } - symbol(&tanq, "tanq"); + symbol(&__tanx, "__tanx"); + symbol(&tanq, "tanf128"); symbol(&tanl, "tanl"); } -pub fn tanh(x: f16) callconv(.c) f16 { +fn __tanh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(tan_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn tan_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(tanf(x)); + return @floatCast(tan_f32(x)); } -pub fn tanf(x: f32) callconv(.c) f32 { +fn tanf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(tan_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn tan_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -90,7 +93,10 @@ pub fn tanf(x: f32) callconv(.c) f32 { return kernel.tandf(y, n & 1 != 0); } -pub fn tan(x: f64) callconv(.c) f64 { +fn tan(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(tan_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn tan_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -120,7 +126,10 @@ pub fn tan(x: f64) callconv(.c) f64 { return kernel.tan(y[0], y[1], n & 1 != 0); } -pub fn tanx(x: f80) callconv(.c) f80 { +fn __tanx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(tan_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn tan_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -141,7 +150,10 @@ pub fn tanx(x: f80) callconv(.c) f80 { return kernel.tanx(y[0], y[1], n & 1); } -pub fn tanq(x: f128) callconv(.c) f128 { +fn tanq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(tan_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn tan_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -164,18 +176,21 @@ pub fn tanq(x: f128) callconv(.c) f128 { pub fn tanl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return tan(x), - 80 => return tanx(x), - 128 => return tanq(x), - else => @compileError("unreachable"), + 64 => return tan_f64(x), + 80 => return tan_f80(x), + 128 => return tan_f128(x), + else => comptime unreachable, } } fn testTanNormal(comptime T: type) !void { const f = switch (T) { - f32 => tanf, - f64 => tan, - else => @compileError("unimplemented"), + f16 => tan_f16, + f32 => tan_f32, + f64 => tan_f64, + f80 => tan_f80, + f128 => tan_f128, + else => comptime unreachable, }; const epsilon = 0.00001; @@ -189,11 +204,12 @@ fn testTanNormal(comptime T: type) !void { fn testTanSpecial(comptime T: type) !void { const f = switch (T) { - f32 => tanf, - f64 => tan, - f80 => tanx, - f128 => tanq, - else => @compileError("unimplemented"), + f16 => tan_f16, + f32 => tan_f32, + f64 => tan_f64, + f80 => tan_f80, + f128 => tan_f128, + else => comptime unreachable, }; try expect(math.isPositiveZero(f(0.0))); @@ -214,23 +230,23 @@ test "tan64.normal" { test "tan80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 0.0), tanx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.2027100355086724833213582716475345), tanx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 1.2404217445497097995561220131857544), tanx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 14.10141994717171938764), tanx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.25439607116885656232), tanx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 2.2858376251355320963), tanx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 0.0), tan_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.2027100355086724833213582716475345), tan_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 1.2404217445497097995561220131857544), tan_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 14.10141994717171938764), tan_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.25439607116885656232), tan_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 2.2858376251355320963), tan_f80(89.123), epsilon); } test "tan128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 0.0), tanq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.2027100355086724833213582716475345), tanq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 1.2404217445497097995561220131857544), tanq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 14.101419947171719387646083651987755), tanq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.2543960711688565630469573224504774), tanq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 2.2858376251355321074066028114094292), tanq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 0.0), tan_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.2027100355086724833213582716475345), tan_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 1.2404217445497097995561220131857544), tan_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 14.101419947171719387646083651987755), tan_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.2543960711688565630469573224504774), tan_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 2.2858376251355321074066028114094292), tan_f128(89.123), epsilon); } test "tan32.special" { diff --git a/lib/compiler_rt/trunc.zig b/lib/compiler_rt/trunc.zig index aa2eb560dfd8035f14aa07c8e51c5c117daad042..0dbacf0e9d822385a8dc558a29bf0401f6d97e21 100644 --- a/lib/compiler_rt/trunc.zig +++ b/lib/compiler_rt/trunc.zig @@ -17,19 +17,22 @@ comptime { symbol(&truncf, "truncf"); symbol(&trunc, "trunc"); symbol(&__truncx, "__truncx"); - if (compiler_rt.want_ppc_abi) { - symbol(&truncq, "truncf128"); - } - symbol(&truncq, "truncq"); + symbol(&truncq, "truncf128"); symbol(&truncl, "truncl"); } -pub fn __trunch(x: f16) callconv(.c) f16 { +fn __trunch(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(trunc_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn trunc_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(truncf(x)); + return @floatCast(trunc_f32(x)); } -pub fn truncf(x: f32) callconv(.c) f32 { +fn truncf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(trunc_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn trunc_f32(x: f32) f32 { const u: u32 = @bitCast(x); var e = @as(i32, @intCast(((u >> 23) & 0xFF))) - 0x7F + 9; var m: u32 = undefined; @@ -50,7 +53,10 @@ pub fn truncf(x: f32) callconv(.c) f32 { } } -pub fn trunc(x: f64) callconv(.c) f64 { +fn trunc(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(trunc_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn trunc_f64(x: f64) f64 { const u: u64 = @bitCast(x); var e = @as(i32, @intCast(((u >> 52) & 0x7FF))) - 0x3FF + 12; var m: u64 = undefined; @@ -71,12 +77,18 @@ pub fn trunc(x: f64) callconv(.c) f64 { } } -pub fn __truncx(x: f80) callconv(.c) f80 { +fn __truncx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(trunc_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn trunc_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(truncq(x)); + return @floatCast(trunc_f128(x)); } -pub fn truncq(x: f128) callconv(.c) f128 { +fn truncq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(trunc_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn trunc_f128(x: f128) f128 { const u: u128 = @bitCast(x); var e = @as(i32, @intCast(((u >> 112) & 0x7FFF))) - 0x3FFF + 16; var m: u128 = undefined; @@ -99,51 +111,69 @@ pub fn truncq(x: f128) callconv(.c) f128 { pub fn truncl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return trunc(x), - 80 => return __truncx(x), - 128 => return truncq(x), - else => @compileError("unreachable"), + 64 => return trunc_f64(x), + 80 => return trunc_f80(x), + 128 => return trunc_f128(x), + else => comptime unreachable, } } -test "trunc32" { - try expect(truncf(1.3) == 1.0); - try expect(truncf(-1.3) == -1.0); - try expect(truncf(0.2) == 0.0); +test trunc_f16 { + try expect(trunc_f16(1.3) == 1.0); + try expect(trunc_f16(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f16(0.2))); + try expect(math.isNegativeZero(trunc_f16(-0.2))); + try expect(math.isPositiveZero(trunc_f16(0.0))); + try expect(math.isNegativeZero(trunc_f16(-0.0))); + try expect(math.isPositiveInf(trunc_f16(math.inf(f32)))); + try expect(math.isNegativeInf(trunc_f16(-math.inf(f32)))); + try expect(math.isNan(trunc_f16(math.nan(f32)))); } -test "trunc64" { - try expect(trunc(1.3) == 1.0); - try expect(trunc(-1.3) == -1.0); - try expect(trunc(0.2) == 0.0); +test trunc_f32 { + try expect(trunc_f32(1.3) == 1.0); + try expect(trunc_f32(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f32(0.2))); + try expect(math.isNegativeZero(trunc_f32(-0.2))); + try expect(math.isPositiveZero(trunc_f32(0.0))); + try expect(math.isNegativeZero(trunc_f32(-0.0))); + try expect(math.isPositiveInf(trunc_f32(math.inf(f32)))); + try expect(math.isNegativeInf(trunc_f32(-math.inf(f32)))); + try expect(math.isNan(trunc_f32(math.nan(f32)))); } -test "trunc128" { - try expect(truncq(1.3) == 1.0); - try expect(truncq(-1.3) == -1.0); - try expect(truncq(0.2) == 0.0); +test trunc_f64 { + try expect(trunc_f64(1.3) == 1.0); + try expect(trunc_f64(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f64(0.2))); + try expect(math.isNegativeZero(trunc_f64(-0.2))); + try expect(math.isPositiveZero(trunc_f64(0.0))); + try expect(math.isNegativeZero(trunc_f64(-0.0))); + try expect(math.isPositiveInf(trunc_f64(math.inf(f64)))); + try expect(math.isNegativeInf(trunc_f64(-math.inf(f64)))); + try expect(math.isNan(trunc_f64(math.nan(f64)))); } -test "trunc32.special" { - try expect(truncf(0.0) == 0.0); // 0x3F800000 - try expect(truncf(-0.0) == -0.0); - try expect(math.isPositiveInf(truncf(math.inf(f32)))); - try expect(math.isNegativeInf(truncf(-math.inf(f32)))); - try expect(math.isNan(truncf(math.nan(f32)))); +test trunc_f80 { + try expect(trunc_f80(1.3) == 1.0); + try expect(trunc_f80(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f80(0.2))); + try expect(math.isNegativeZero(trunc_f80(-0.2))); + try expect(math.isPositiveZero(trunc_f80(0.0))); + try expect(math.isNegativeZero(trunc_f80(-0.0))); + try expect(math.isPositiveInf(trunc_f80(math.inf(f64)))); + try expect(math.isNegativeInf(trunc_f80(-math.inf(f64)))); + try expect(math.isNan(trunc_f80(math.nan(f64)))); } -test "trunc64.special" { - try expect(trunc(0.0) == 0.0); - try expect(trunc(-0.0) == -0.0); - try expect(math.isPositiveInf(trunc(math.inf(f64)))); - try expect(math.isNegativeInf(trunc(-math.inf(f64)))); - try expect(math.isNan(trunc(math.nan(f64)))); -} - -test "trunc128.special" { - try expect(truncq(0.0) == 0.0); - try expect(truncq(-0.0) == -0.0); - try expect(math.isPositiveInf(truncq(math.inf(f128)))); - try expect(math.isNegativeInf(truncq(-math.inf(f128)))); - try expect(math.isNan(truncq(math.nan(f128)))); +test trunc_f128 { + try expect(trunc_f128(1.3) == 1.0); + try expect(trunc_f128(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f128(0.2))); + try expect(math.isNegativeZero(trunc_f128(-0.2))); + try expect(math.isPositiveZero(trunc_f128(0.0))); + try expect(math.isNegativeZero(trunc_f128(-0.0))); + try expect(math.isPositiveInf(trunc_f128(math.inf(f128)))); + try expect(math.isNegativeInf(trunc_f128(-math.inf(f128)))); + try expect(math.isNan(trunc_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/truncdfhf2.zig b/lib/compiler_rt/truncdfhf2.zig deleted file mode 100644 index e01e1877633eee7077c64ef42e6cde56a0a17aee..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncdfhf2.zig +++ /dev/null @@ -1,18 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const truncf = @import("./truncf.zig").truncf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2h, "__aeabi_d2h"); - } - symbol(&__truncdfhf2, "__truncdfhf2"); -} - -pub fn __truncdfhf2(a: f64) callconv(.c) compiler_rt.F16T(f64) { - return @bitCast(truncf(f16, f64, a)); -} - -fn __aeabi_d2h(a: f64) callconv(.{ .arm_aapcs = .{} }) u16 { - return @bitCast(truncf(f16, f64, a)); -} diff --git a/lib/compiler_rt/truncdfsf2.zig b/lib/compiler_rt/truncdfsf2.zig deleted file mode 100644 index f1bada18449130344f213ad0f8272794d38f23bf..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncdfsf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2f, "__aeabi_d2f"); - } else { - symbol(&__truncdfsf2, "__truncdfsf2"); - } -} - -pub fn __truncdfsf2(a: f64) callconv(.c) f32 { - return truncf(f32, f64, a); -} - -fn __aeabi_d2f(a: f64) callconv(.{ .arm_aapcs = .{} }) f32 { - return truncf(f32, f64, a); -} diff --git a/lib/compiler_rt/truncf.zig b/lib/compiler_rt/truncf.zig index a03f3b67113028ba8a69c4fc72023b9d26f87e23..9a1cb491e27bc214a2c5c7a4a91f8f236efae1ef 100644 --- a/lib/compiler_rt/truncf.zig +++ b/lib/compiler_rt/truncf.zig @@ -1,6 +1,204 @@ const std = @import("std"); -pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + if (compiler_rt.want_aeabi) { + if (compiler_rt.gnu_f16_abi) { + symbol(&__aeabi_f2h, "__gnu_f2h_ieee"); + } else { + symbol(&__aeabi_f2h, "__aeabi_f2h"); + } + symbol(&__aeabi_d2h, "__aeabi_d2h"); + } else if (compiler_rt.gnu_f16_abi) { + symbol(&__truncsfhf2, "__gnu_f2h_ieee"); + } + symbol(&__truncsfhf2, "__truncsfhf2"); + symbol(&__truncdfhf2, "__truncdfhf2"); + symbol(&__truncxfhf2, "__truncxfhf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfhf2, "__trunckfhf2"); + } else { + symbol(&__trunctfhf2, "__trunctfhf2"); + } + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2f, "__aeabi_d2f"); + } else { + symbol(&__truncdfsf2, "__truncdfsf2"); + } + symbol(&__truncxfsf2, "__truncxfsf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfsf2, "__trunckfsf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtos, "_Qp_qtos"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__trunctfsf2, "_Q_qtos"); + } else { + symbol(&__trunctfsf2, "__trunctfsf2"); + } + + symbol(&__truncxfdf2, "__truncxfdf2"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfdf2, "__trunckfdf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtod, "_Qp_qtod"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__trunctfdf2, "_Q_qtod"); + } else { + symbol(&__trunctfdf2, "__trunctfdf2"); + } + + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfxf2, "__trunckfxf2"); + } else { + symbol(&__trunctfxf2, "__trunctfxf2"); + } +} + +fn __truncsfhf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f16Conv(f32).Abi { + return compiler_rt.f16Conv(f32).toAbi(f16_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn __aeabi_f2h(a: u32) callconv(.{ .arm_aapcs = .{} }) u16 { + return @bitCast(f16_floatCast_f32(@bitCast(a))); +} +pub fn f16_floatCast_f32(a: f32) f16 { + return truncf(f16, f32, a); +} + +fn __truncdfhf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f16Conv(f64).Abi { + return compiler_rt.f16Conv(f64).toAbi(f16_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn __aeabi_d2h(a: u64) callconv(.{ .arm_aapcs = .{} }) u16 { + return @bitCast(f16_floatCast_f64(@bitCast(a))); +} +pub fn f16_floatCast_f64(a: f64) f16 { + return truncf(f16, f64, a); +} + +fn __truncxfhf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f16Conv(f80).Abi { + return compiler_rt.f16Conv(f80).toAbi(f16_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f16_floatCast_f80(a: f80) f16 { + return trunc_f80(f16, a); +} + +fn __trunctfhf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f16Conv(f128).Abi { + return compiler_rt.f16Conv(f128).toAbi(f16_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn f16_floatCast_f128(a: f128) f16 { + return truncf(f16, f128, a); +} + +fn __truncdfsf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn __aeabi_d2f(a: f64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatCast_f64(a); +} +pub fn f32_floatCast_f64(a: f64) f32 { + return truncf(f32, f64, a); +} + +fn __truncxfsf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f32_floatCast_f80(a: f80) f32 { + return trunc_f80(f32, a); +} + +fn __trunctfsf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +fn _Qp_qtos(a: *const f128) callconv(.c) f32 { + return f32_floatCast_f128(a.*); +} +pub fn f32_floatCast_f128(a: f128) f32 { + return truncf(f32, f128, a); +} + +fn __truncxfdf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f64_floatCast_f80(a: f80) f64 { + return trunc_f80(f64, a); +} + +fn __trunctfdf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +fn _Qp_qtod(a: *const f128) callconv(.c) f64 { + return f64_floatCast_f128(a.*); +} +pub fn f64_floatCast_f128(a: f128) f64 { + return truncf(f64, f128, a); +} + +fn __trunctfxf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn f80_floatCast_f128(a: f128) f80 { + const src_sig_bits = std.math.floatMantissaBits(f128); + const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const src_bits = @typeInfo(f128).float.bits; + const src_exp_bits = src_bits - src_sig_bits - 1; + const src_inf_exp = 0x7FFF; + + const src_inf = src_inf_exp << src_sig_bits; + const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); + const src_abs_mask = src_sign_mask - 1; + const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; + const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); + + // Break a into a sign and representation of the absolute value + const a_rep: u128 = @bitCast(a); + const a_abs = a_rep & src_abs_mask; + const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; + const integer_bit = 1 << 63; + + var res: std.math.F80 = undefined; + + if (a_abs > src_inf) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + res.exp = 0x7fff; + res.fraction = 0x8000000000000000; + res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))); + } else { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding, adding the explicit integer bit, and adjusting the exponent + res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit; + res.exp = @truncate(a_abs >> src_sig_bits); + + const round_bits = a_abs & round_mask; + if (round_bits > halfway) { + // Round to nearest + const ov = @addWithOverflow(res.fraction, 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry + } else if (round_bits == halfway) { + // Ties to even + const ov = @addWithOverflow(res.fraction, res.fraction & 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry + } + if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals + } + + res.exp |= sign; + return res.toFloat(); +} + +inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); @@ -99,7 +297,7 @@ pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t return @bitCast(result); } -pub inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { +inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit const dst_sig_bits = std.math.floatMantissaBits(dst_t); diff --git a/lib/compiler_rt/truncf_test.zig b/lib/compiler_rt/truncf_test.zig index 8da6fe0a19456e9898f32ea4dec4c7b8ccb221b4..6595c47b52d8f868d019c1728ae3d57735e12323 100644 --- a/lib/compiler_rt/truncf_test.zig +++ b/lib/compiler_rt/truncf_test.zig @@ -1,79 +1,82 @@ const std = @import("std"); const testing = std.testing; -const __truncsfhf2 = @import("truncsfhf2.zig").__truncsfhf2; -const __truncdfhf2 = @import("truncdfhf2.zig").__truncdfhf2; -const __truncdfsf2 = @import("truncdfsf2.zig").__truncdfsf2; -const __trunctfhf2 = @import("trunctfhf2.zig").__trunctfhf2; -const __trunctfsf2 = @import("trunctfsf2.zig").__trunctfsf2; -const __trunctfdf2 = @import("trunctfdf2.zig").__trunctfdf2; -const __trunctfxf2 = @import("trunctfxf2.zig").__trunctfxf2; - -fn test__truncsfhf2(a: u32, expected: u16) !void { - const actual: u16 = @bitCast(__truncsfhf2(@bitCast(a))); - - if (actual == expected) { - return; - } - - return error.TestFailure; +const impl = @import("truncf.zig"); + +const f16_floatCast_f32 = impl.f16_floatCast_f32; +const f16_floatCast_f64 = impl.f16_floatCast_f64; +const f16_floatCast_f80 = impl.f16_floatCast_f80; +const f16_floatCast_f128 = impl.f16_floatCast_f128; + +const f32_floatCast_f64 = impl.f32_floatCast_f64; +const f32_floatCast_f80 = impl.f32_floatCast_f80; +const f32_floatCast_f128 = impl.f32_floatCast_f128; + +const f64_floatCast_f80 = impl.f64_floatCast_f80; +const f64_floatCast_f128 = impl.f64_floatCast_f128; + +const f80_floatCast_f128 = impl.f80_floatCast_f128; + +fn test_f16_floatCast_f32(a: u32, expected: u16) !void { + const actual: u16 = @bitCast(f16_floatCast_f32(@bitCast(a))); + try testing.expect(actual == expected); } -test "truncsfhf2" { - try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN - try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN +test f16_floatCast_f32 { + try test_f16_floatCast_f32(0x7fc00000, 0x7e00); // qNaN + try test_f16_floatCast_f32(0x7fe00000, 0x7f00); // sNaN - try test__truncsfhf2(0, 0); // 0 - try test__truncsfhf2(0x80000000, 0x8000); // -0 + try test_f16_floatCast_f32(0, 0); // 0 + try test_f16_floatCast_f32(0x80000000, 0x8000); // -0 - try test__truncsfhf2(0x7f800000, 0x7c00); // inf - try test__truncsfhf2(0xff800000, 0xfc00); // -inf + try test_f16_floatCast_f32(0x7f800000, 0x7c00); // inf + try test_f16_floatCast_f32(0xff800000, 0xfc00); // -inf - try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf - try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf + try test_f16_floatCast_f32(0x477ff000, 0x7c00); // 65520 -> inf + try test_f16_floatCast_f32(0xc77ff000, 0xfc00); // -65520 -> -inf - try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf - try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf + try test_f16_floatCast_f32(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf + try test_f16_floatCast_f32(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf - try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 - try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 + try test_f16_floatCast_f32(0x38800000, 0x0400); // normal (min), 2**-14 + try test_f16_floatCast_f32(0xb8800000, 0x8400); // normal (min), -2**-14 - try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 - try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 + try test_f16_floatCast_f32(0x477fe000, 0x7bff); // normal (max), 65504 + try test_f16_floatCast_f32(0xc77fe000, 0xfbff); // normal (max), -65504 - try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 - try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 + try test_f16_floatCast_f32(0x477fe100, 0x7bff); // normal, 65505 -> 65504 + try test_f16_floatCast_f32(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 - try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 - try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 + try test_f16_floatCast_f32(0x477fef00, 0x7bff); // normal, 65519 -> 65504 + try test_f16_floatCast_f32(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 - try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 - try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 + try test_f16_floatCast_f32(0x3f802000, 0x3c01); // normal, 1 + 2**-10 + try test_f16_floatCast_f32(0xbf802000, 0xbc01); // normal, -1 - 2**-10 - try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 - try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 + try test_f16_floatCast_f32(0x3eaaa000, 0x3555); // normal, approx. 1/3 + try test_f16_floatCast_f32(0xbeaaa000, 0xb555); // normal, approx. -1/3 - try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 - try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 + try test_f16_floatCast_f32(0x40490fdb, 0x4248); // normal, 3.1415926535 + try test_f16_floatCast_f32(0xc0490fdb, 0xc248); // normal, -3.1415926535 - try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 + try test_f16_floatCast_f32(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 - try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 - try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 + try test_f16_floatCast_f32(0x3f800000, 0x3c00); // normal, 1 + try test_f16_floatCast_f32(0x38800000, 0x0400); // normal, 0x1.0p-14 - try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 - try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 + try test_f16_floatCast_f32(0x33800000, 0x0001); // denormal (min), 2**-24 + try test_f16_floatCast_f32(0xb3800000, 0x8001); // denormal (min), -2**-24 - try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 - try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 + try test_f16_floatCast_f32(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 + try test_f16_floatCast_f32(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 - try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 - try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 - try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero + try test_f16_floatCast_f32(0x35800000, 0x0010); // denormal, 0x1.0p-20 + try test_f16_floatCast_f32(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 + try test_f16_floatCast_f32(0x33000000, 0x0000); // 0x1.0p-25 -> zero } -fn test__truncdfhf2(a: f64, expected: u16) void { - const rep: u16 = @bitCast(__truncdfhf2(a)); +fn test_f16_floatCast_f64(a: f64, expected: u16) !void { + const rep: u16 = @bitCast(f16_floatCast_f64(a)); if (rep == expected) { return; @@ -84,62 +87,56 @@ fn test__truncdfhf2(a: f64, expected: u16) void { return; } } - - @panic("__truncdfhf2 test failure"); + return error.TestFailure; } -fn test__truncdfhf2_raw(a: u64, expected: u16) void { - const actual: u16 = @bitCast(__truncdfhf2(@bitCast(a))); - - if (actual == expected) { - return; - } - - @panic("__truncdfhf2 test failure"); +fn test_f16_floatCast_f64_raw(a: u64, expected: u16) !void { + const actual: u16 = @bitCast(f16_floatCast_f64(@bitCast(a))); + try testing.expect(actual == expected); } -test "truncdfhf2" { - test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN - test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN +test f16_floatCast_f64 { + try test_f16_floatCast_f64_raw(0x7ff8000000000000, 0x7e00); // qNaN + try test_f16_floatCast_f64_raw(0x7ff0000000008000, 0x7e00); // NaN - test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf - test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf + try test_f16_floatCast_f64_raw(0x7ff0000000000000, 0x7c00); //inf + try test_f16_floatCast_f64_raw(0xfff0000000000000, 0xfc00); // -inf - test__truncdfhf2(0.0, 0x0); // zero - test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero + try test_f16_floatCast_f64(0.0, 0x0); // zero + try test_f16_floatCast_f64_raw(0x80000000 << 32, 0x8000); // -zero - test__truncdfhf2(3.1415926535, 0x4248); - test__truncdfhf2(-3.1415926535, 0xc248); + try test_f16_floatCast_f64(3.1415926535, 0x4248); + try test_f16_floatCast_f64(-3.1415926535, 0xc248); - test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); - test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); - test__truncdfhf2(0x1.0p+0, 0x3c00); - test__truncdfhf2(0x1.0p-14, 0x0400); + try test_f16_floatCast_f64(0x1.987124876876324p+1000, 0x7c00); + try test_f16_floatCast_f64(0x1.987124876876324p+12, 0x6e62); + try test_f16_floatCast_f64(0x1.0p+0, 0x3c00); + try test_f16_floatCast_f64(0x1.0p-14, 0x0400); // denormal - test__truncdfhf2(0x1.0p-20, 0x0010); - test__truncdfhf2(0x1.0p-24, 0x0001); - test__truncdfhf2(-0x1.0p-24, 0x8001); - test__truncdfhf2(0x1.5p-25, 0x0001); + try test_f16_floatCast_f64(0x1.0p-20, 0x0010); + try test_f16_floatCast_f64(0x1.0p-24, 0x0001); + try test_f16_floatCast_f64(-0x1.0p-24, 0x8001); + try test_f16_floatCast_f64(0x1.5p-25, 0x0001); // and back to zero - test__truncdfhf2(0x1.0p-25, 0x0000); - test__truncdfhf2(-0x1.0p-25, 0x8000); + try test_f16_floatCast_f64(0x1.0p-25, 0x0000); + try test_f16_floatCast_f64(-0x1.0p-25, 0x8000); // max (precise) - test__truncdfhf2(65504.0, 0x7bff); + try test_f16_floatCast_f64(65504.0, 0x7bff); // max (rounded) - test__truncdfhf2(65519.0, 0x7bff); + try test_f16_floatCast_f64(65519.0, 0x7bff); // max (to +inf) - test__truncdfhf2(65520.0, 0x7c00); - test__truncdfhf2(-65520.0, 0xfc00); - test__truncdfhf2(65536.0, 0x7c00); + try test_f16_floatCast_f64(65520.0, 0x7c00); + try test_f16_floatCast_f64(-65520.0, 0xfc00); + try test_f16_floatCast_f64(65536.0, 0x7c00); } -fn test__trunctfsf2(a: f128, expected: u32) void { - const x = __trunctfsf2(a); +fn test_f32_floatCast_f128(a: f128, expected: u32) !void { + const x = f32_floatCast_f128(a); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -151,28 +148,27 @@ fn test__trunctfsf2(a: f128, expected: u32) void { return; } } - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "trunctfsf2" { +test f32_floatCast_f128 { // qnan - test__trunctfsf2(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); + try test_f32_floatCast_f128(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); // nan - test__trunctfsf2(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); + try test_f32_floatCast_f128(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); // inf - test__trunctfsf2(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7f800000); + try test_f32_floatCast_f128(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7f800000); // zero - test__trunctfsf2(0.0, 0x0); + try test_f32_floatCast_f128(0.0, 0x0); - test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); - test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); - test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); - test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); + try test_f32_floatCast_f128(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); + try test_f32_floatCast_f128(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); + try test_f32_floatCast_f128(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); + try test_f32_floatCast_f128(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); } -fn test__trunctfdf2(a: f128, expected: u64) void { - const x = __trunctfdf2(a); +fn test_f64_floatCast_f128(a: f128, expected: u64) !void { + const x = f64_floatCast_f128(a); const rep: u64 = @bitCast(x); if (rep == expected) { @@ -184,28 +180,27 @@ fn test__trunctfdf2(a: f128, expected: u64) void { return; } } - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "trunctfdf2" { +test f64_floatCast_f128 { // qnan - test__trunctfdf2(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); // nan - test__trunctfdf2(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); // inf - test__trunctfdf2(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); // zero - test__trunctfdf2(0.0, 0x0); + try test_f64_floatCast_f128(0.0, 0x0); - test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); - test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); - test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); - test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); + try test_f64_floatCast_f128(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); + try test_f64_floatCast_f128(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); + try test_f64_floatCast_f128(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); + try test_f64_floatCast_f128(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); } -fn test__truncdfsf2(a: f64, expected: u32) void { - const x = __truncdfsf2(a); +fn test_f32_floatCast_f64(a: f64, expected: u32) !void { + const x = f32_floatCast_f64(a); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -217,90 +212,81 @@ fn test__truncdfsf2(a: f64, expected: u32) void { return; } } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "truncdfsf2" { +test f32_floatCast_f64 { // nan & qnan - test__truncdfsf2(@bitCast(@as(u64, 0x7ff8000000000000)), 0x7fc00000); - test__truncdfsf2(@bitCast(@as(u64, 0x7ff0000000000001)), 0x7fc00000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff8000000000000)), 0x7fc00000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff0000000000001)), 0x7fc00000); // inf - test__truncdfsf2(@bitCast(@as(u64, 0x7ff0000000000000)), 0x7f800000); - test__truncdfsf2(@bitCast(@as(u64, 0xfff0000000000000)), 0xff800000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff0000000000000)), 0x7f800000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0xfff0000000000000)), 0xff800000); - test__truncdfsf2(0.0, 0x0); - test__truncdfsf2(1.0, 0x3f800000); - test__truncdfsf2(-1.0, 0xbf800000); + try test_f32_floatCast_f64(0.0, 0x0); + try test_f32_floatCast_f64(1.0, 0x3f800000); + try test_f32_floatCast_f64(-1.0, 0xbf800000); // huge number becomes inf - test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); + try test_f32_floatCast_f64(340282366920938463463374607431768211456.0, 0x7f800000); } -fn test__trunctfhf2(a: f128, expected: u16) void { - const x = __trunctfhf2(a); +fn test_f16_floatCast_f128(a: f128, expected: u16) !void { + const x = f16_floatCast_f128(a); const rep: u16 = @bitCast(x); - if (rep == expected) { - return; - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfhf2 test failure"); + try testing.expect(rep == expected); } -test "trunctfhf2" { +test f16_floatCast_f128 { // qNaN - test__trunctfhf2(@bitCast(@as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); // NaN - test__trunctfhf2(@bitCast(@as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); // inf - test__trunctfhf2(@bitCast(@as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); - test__trunctfhf2(-@as(f128, @bitCast(@as(u128, 0x7fff0000000000000000000000000000))), 0xfc00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); + try test_f16_floatCast_f128(-@as(f128, @bitCast(@as(u128, 0x7fff0000000000000000000000000000))), 0xfc00); // zero - test__trunctfhf2(0.0, 0x0); - test__trunctfhf2(-0.0, 0x8000); + try test_f16_floatCast_f128(0.0, 0x0); + try test_f16_floatCast_f128(-0.0, 0x8000); - test__trunctfhf2(3.1415926535, 0x4248); - test__trunctfhf2(-3.1415926535, 0xc248); - test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); - test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); - test__trunctfhf2(0x1.0p+0, 0x3c00); - test__trunctfhf2(0x1.0p-14, 0x0400); + try test_f16_floatCast_f128(3.1415926535, 0x4248); + try test_f16_floatCast_f128(-3.1415926535, 0xc248); + try test_f16_floatCast_f128(0x1.987124876876324p+100, 0x7c00); + try test_f16_floatCast_f128(0x1.987124876876324p+12, 0x6e62); + try test_f16_floatCast_f128(0x1.0p+0, 0x3c00); + try test_f16_floatCast_f128(0x1.0p-14, 0x0400); // denormal - test__trunctfhf2(0x1.0p-20, 0x0010); - test__trunctfhf2(0x1.0p-24, 0x0001); - test__trunctfhf2(-0x1.0p-24, 0x8001); - test__trunctfhf2(0x1.5p-25, 0x0001); + try test_f16_floatCast_f128(0x1.0p-20, 0x0010); + try test_f16_floatCast_f128(0x1.0p-24, 0x0001); + try test_f16_floatCast_f128(-0x1.0p-24, 0x8001); + try test_f16_floatCast_f128(0x1.5p-25, 0x0001); // and back to zero - test__trunctfhf2(0x1.0p-25, 0x0000); - test__trunctfhf2(-0x1.0p-25, 0x8000); + try test_f16_floatCast_f128(0x1.0p-25, 0x0000); + try test_f16_floatCast_f128(-0x1.0p-25, 0x8000); // max (precise) - test__trunctfhf2(65504.0, 0x7bff); + try test_f16_floatCast_f128(65504.0, 0x7bff); // max (rounded) - test__trunctfhf2(65519.0, 0x7bff); + try test_f16_floatCast_f128(65519.0, 0x7bff); // max (to +inf) - test__trunctfhf2(65520.0, 0x7c00); - test__trunctfhf2(65536.0, 0x7c00); - test__trunctfhf2(-65520.0, 0xfc00); + try test_f16_floatCast_f128(65520.0, 0x7c00); + try test_f16_floatCast_f128(65536.0, 0x7c00); + try test_f16_floatCast_f128(-65520.0, 0xfc00); - test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); - test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); - test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); - test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); + try test_f16_floatCast_f128(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); + try test_f16_floatCast_f128(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); + try test_f16_floatCast_f128(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); + try test_f16_floatCast_f128(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); } -test "trunctfxf2" { - try test__trunctfxf2(1.5, 1.5); - try test__trunctfxf2(2.5, 2.5); - try test__trunctfxf2(-2.5, -2.5); - try test__trunctfxf2(0.0, 0.0); -} - -fn test__trunctfxf2(a: f128, expected: f80) !void { - const x = __trunctfxf2(a); +fn test_f80_floatCast_f128(a: f128, expected: f80) !void { + const x = f80_floatCast_f128(a); try testing.expect(x == expected); } + +test f80_floatCast_f128 { + try test_f80_floatCast_f128(1.5, 1.5); + try test_f80_floatCast_f128(2.5, 2.5); + try test_f80_floatCast_f128(-2.5, -2.5); + try test_f80_floatCast_f128(0.0, 0.0); +} diff --git a/lib/compiler_rt/truncsfhf2.zig b/lib/compiler_rt/truncsfhf2.zig deleted file mode 100644 index e0b2b1e4bf2f15400c568f1c1656c8cb70bc03c8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncsfhf2.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.gnu_f16_abi) { - symbol(&__gnu_f2h_ieee, "__gnu_f2h_ieee"); - } else if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2h, "__aeabi_f2h"); - } - symbol(&__truncsfhf2, "__truncsfhf2"); -} - -pub fn __truncsfhf2(a: f32) callconv(.c) compiler_rt.F16T(f32) { - return @bitCast(truncf(f16, f32, a)); -} - -fn __gnu_f2h_ieee(a: f32) callconv(.c) compiler_rt.F16T(f32) { - return @bitCast(truncf(f16, f32, a)); -} - -fn __aeabi_f2h(a: f32) callconv(.{ .arm_aapcs = .{} }) u16 { - return @bitCast(truncf(f16, f32, a)); -} diff --git a/lib/compiler_rt/trunctfdf2.zig b/lib/compiler_rt/trunctfdf2.zig deleted file mode 100644 index ba909de73bf144b2f023e4f6366dac5a4ad0ea40..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfdf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfdf2, "__trunckfdf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtod, "_Qp_qtod"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__trunctfdf2, "_Q_qtod"); - } - symbol(&__trunctfdf2, "__trunctfdf2"); -} - -pub fn __trunctfdf2(a: f128) callconv(.c) f64 { - return truncf(f64, f128, a); -} - -fn _Qp_qtod(a: *const f128) callconv(.c) f64 { - return truncf(f64, f128, a.*); -} diff --git a/lib/compiler_rt/trunctfhf2.zig b/lib/compiler_rt/trunctfhf2.zig deleted file mode 100644 index 5af87f9c127180b49a15b8f3906252d7da162d26..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfhf2.zig +++ /dev/null @@ -1,14 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - symbol(&__trunctfhf2, "__trunctfhf2"); - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfhf2, "__trunckfhf2"); - } -} - -pub fn __trunctfhf2(a: f128) callconv(.c) compiler_rt.F16T(f128) { - return @bitCast(truncf(f16, f128, a)); -} diff --git a/lib/compiler_rt/trunctfsf2.zig b/lib/compiler_rt/trunctfsf2.zig deleted file mode 100644 index 8af51ca82f95b1dd36c7f27df20e6756b8e15396..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfsf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const truncf = @import("./truncf.zig").truncf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfsf2, "__trunckfsf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtos, "_Qp_qtos"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__trunctfsf2, "_Q_qtos"); - } - symbol(&__trunctfsf2, "__trunctfsf2"); -} - -pub fn __trunctfsf2(a: f128) callconv(.c) f32 { - return truncf(f32, f128, a); -} - -fn _Qp_qtos(a: *const f128) callconv(.c) f32 { - return truncf(f32, f128, a.*); -} diff --git a/lib/compiler_rt/trunctfxf2.zig b/lib/compiler_rt/trunctfxf2.zig deleted file mode 100644 index dfb9ef80402cda0360a111e436ba1f7c460bbc1f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfxf2.zig +++ /dev/null @@ -1,67 +0,0 @@ -const math = @import("std").math; -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__trunctfxf2, "__trunctfxf2"); -} - -pub fn __trunctfxf2(a: f128) callconv(.c) f80 { - const src_sig_bits = math.floatMantissaBits(f128); - const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const src_bits = @typeInfo(f128).float.bits; - const src_exp_bits = src_bits - src_sig_bits - 1; - const src_inf_exp = 0x7FFF; - - const src_inf = src_inf_exp << src_sig_bits; - const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); - const src_abs_mask = src_sign_mask - 1; - const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; - const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); - - // Break a into a sign and representation of the absolute value - const a_rep = @as(u128, @bitCast(a)); - const a_abs = a_rep & src_abs_mask; - const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; - const integer_bit = 1 << 63; - - var res: math.F80 = undefined; - - if (a_abs > src_inf) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - res.exp = 0x7fff; - res.fraction = 0x8000000000000000; - res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))); - } else { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding, adding the explicit integer bit, and adjusting the exponent - res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit; - res.exp = @truncate(a_abs >> src_sig_bits); - - const round_bits = a_abs & round_mask; - if (round_bits > halfway) { - // Round to nearest - const ov = @addWithOverflow(res.fraction, 1); - res.fraction = ov[0]; - res.exp += ov[1]; - res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry - } else if (round_bits == halfway) { - // Ties to even - const ov = @addWithOverflow(res.fraction, res.fraction & 1); - res.fraction = ov[0]; - res.exp += ov[1]; - res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry - } - if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals - } - - res.exp |= sign; - return res.toFloat(); -} diff --git a/lib/compiler_rt/truncxfdf2.zig b/lib/compiler_rt/truncxfdf2.zig deleted file mode 100644 index 6140d94181fbe10a5e83e880dff805e87b34fae8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfdf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__truncxfdf2, "__truncxfdf2"); -} - -fn __truncxfdf2(a: f80) callconv(.c) f64 { - return trunc_f80(f64, a); -} diff --git a/lib/compiler_rt/truncxfhf2.zig b/lib/compiler_rt/truncxfhf2.zig deleted file mode 100644 index 4c3e951bfe9b67ff88818e6a89f210851ddfcfb0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfhf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__truncxfhf2, "__truncxfhf2"); -} - -fn __truncxfhf2(a: f80) callconv(.c) compiler_rt.F16T(f80) { - return @bitCast(trunc_f80(f16, a)); -} diff --git a/lib/compiler_rt/truncxfsf2.zig b/lib/compiler_rt/truncxfsf2.zig deleted file mode 100644 index 8aaf7e6906a9da938835d2c36e931bfb21d07037..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfsf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const trunc_f80 = @import("./truncf.zig").trunc_f80; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__truncxfsf2, "__truncxfsf2"); -} - -fn __truncxfsf2(a: f80) callconv(.c) f32 { - return trunc_f80(f32, a); -} diff --git a/lib/compiler_rt/udivmodei4.zig b/lib/compiler_rt/udivmodei4.zig index 41ba32cdbef1532de8b77e0f91db4bbf4b39f29a..e7c4f52cd1f0360307c5e0ab2232c8925b0b1792 100644 --- a/lib/compiler_rt/udivmodei4.zig +++ b/lib/compiler_rt/udivmodei4.zig @@ -6,7 +6,7 @@ const shr = std.math.shr; const shl = std.math.shl; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const max_limbs = @divCeil(65535, 32); // max supported type is u65535 diff --git a/lib/compiler_rt/unorddf2.zig b/lib/compiler_rt/unorddf2.zig deleted file mode 100644 index 90da7451992ab5f8b003e5e2f85f93947f932197..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/unorddf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpun, "__aeabi_dcmpun"); - } else { - symbol(&__unorddf2, "__unorddf2"); - } -} - -pub fn __unorddf2(a: f64, b: f64) callconv(.c) i32 { - return comparef.unordcmp(f64, a, b); -} - -fn __aeabi_dcmpun(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return comparef.unordcmp(f64, a, b); -} diff --git a/lib/std/Io/Semaphore.zig b/lib/std/Io/Semaphore.zig index 1f486750487ed8cd66c39306998d7434e8cd4df7..8f2137b80220fa26c19173d8a3db1098eb24f570 100644 --- a/lib/std/Io/Semaphore.zig +++ b/lib/std/Io/Semaphore.zig @@ -4,8 +4,6 @@ //! This API supports static initialization and does not require deinitialization. const Semaphore = @This(); -const builtin = @import("builtin"); - const std = @import("../std.zig"); const Io = std.Io; const testing = std.testing; diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index ca9564edff39fe329f5114aa2a2fba41c4a6fe02..ebfe6cd502f399501eeafdbdf44205ca6636e8d2 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -874,7 +874,7 @@ pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize { } /// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes. -pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { +pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.lang.Endian) Error!void { var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined; std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); return w.writeAll(&bytes); @@ -882,7 +882,7 @@ pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.built /// The function is inline to avoid the dead code in case `endian` is /// comptime-known and matches host endianness. -pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void { +pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.lang.Endian) Error!void { switch (@typeInfo(@TypeOf(value))) { .@"struct" => |info| switch (info.layout) { .auto => @compileError("ill-defined memory layout"), @@ -907,7 +907,7 @@ pub inline fn writeSliceEndian( w: *Writer, Elem: type, slice: []const Elem, - endian: std.builtin.Endian, + endian: std.lang.Endian, ) Error!void { switch (@typeInfo(Elem)) { .@"struct" => |info| comptime assert(info.layout != .auto), @@ -2817,12 +2817,12 @@ pub const Allocating = struct { } test Allocating { - try testAllocating(.fromByteUnits(1)); - try testAllocating(.fromByteUnits(4)); - try testAllocating(.fromByteUnits(8)); - try testAllocating(.fromByteUnits(16)); - try testAllocating(.fromByteUnits(32)); - try testAllocating(.fromByteUnits(64)); + try testAllocating(.@"1"); + try testAllocating(.@"4"); + try testAllocating(.@"8"); + try testAllocating(.@"16"); + try testAllocating(.@"32"); + try testAllocating(.@"64"); } }; diff --git a/lib/std/Random/RomuTrio.zig b/lib/std/Random/RomuTrio.zig index 9f005bf2f9fac8082eb4e71355dc90c73280d2b9..7352308f0d18eb6ccbe0b506bdfd4138443c89de 100644 --- a/lib/std/Random/RomuTrio.zig +++ b/lib/std/Random/RomuTrio.zig @@ -122,7 +122,6 @@ test fill { } test "buf seeding test" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const buf0: [24]u8 = @bitCast([3]u64{ 16294208416658607535, 13964609475759908645, 4703697494102998476 }); const resulting_state = .{ .x = 16294208416658607535, .y = 13964609475759908645, .z = 4703697494102998476 }; var r = RomuTrio.init(0); diff --git a/lib/std/Random/Xoshiro256.zig b/lib/std/Random/Xoshiro256.zig index 6cb0583d982622b3f7df21b94368b03ddeb80c17..9c1ea9cfec6843cf2b9151ac08cb44aebd810936 100644 --- a/lib/std/Random/Xoshiro256.zig +++ b/lib/std/Random/Xoshiro256.zig @@ -89,8 +89,6 @@ pub fn fill(self: *Xoshiro256, buf: []u8) void { } test "sequence" { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - var r = Xoshiro256.init(0); const seq1 = [_]u64{ diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 6124ffd96597d33dbd1027ae8b5757989b536c7a..2f395dc0f03d6aa5673df31b4aa3bb92d66bf50a 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1797,6 +1797,7 @@ pub const Cpu = struct { .x86_sysv, .x86_win, + .x86_mingw, .x86_stdcall, .x86_fastcall, .x86_thiscall, @@ -3066,9 +3067,13 @@ pub fn stackGrowth(target: *const Target) StackGrowth { /// Default signedness of `char` for the native C compiler for this target /// Note that char signedness is implementation-defined and many compilers provide /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char -pub fn cCharSignedness(target: *const Target) std.builtin.Signedness { +/// Returns `null` if no C ABI is defined for this target. +pub fn cCharSignedness(target: *const Target) ?std.builtin.Signedness { + switch (target.os.tag) { + .opengl => return null, + else => {}, + } if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed; - return switch (target.cpu.arch) { .aarch64, .aarch64_be, @@ -3114,7 +3119,8 @@ pub const CType = enum { longdouble, }; -pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 { return switch (c_type) { .char, .short, @@ -3127,18 +3133,19 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 { .ulonglong, .float, .double, - => @divExact(cTypeBitSize(t, c_type), 8), + => @divExact(cTypeBitSize(t, c_type) orelse return null, 8), - .longdouble => switch (cTypeBitSize(t, c_type)) { + .longdouble => switch (cTypeBitSize(t, c_type) orelse return null) { 64 => 8, - 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))), + 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, c_type).?)), 128 => 16, else => unreachable, }, }; } -pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 { switch (target.os.tag) { .freestanding, .other, @@ -3459,15 +3466,17 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .longlong, .ulonglong, .longdouble => return 64, }, + .opengl => return null, + .ps3, .contiki, .managarm, - .opengl, => @panic("specify the C integer and float type sizes for this OS"), } } -pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 { // Overrides for unusual alignments switch (target.cpu.arch) { .avr, @@ -3500,7 +3509,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { // Next-power-of-two-aligned, up to a maximum. return @min( - std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), + std.math.ceilPowerOfTwoAssert(u16, ((cTypeBitSize(target, c_type) orelse return null) + 7) / 8), @as(u16, switch (target.cpu.arch) { .msp430, .x86_16, @@ -3575,120 +3584,6 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { ); } -pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 { - // Overrides for unusual alignments - switch (target.cpu.arch) { - .arc, .arceb => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - .avr, - .ez80, - => return 1, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (c_type) { - .longdouble => switch (target.abi) { - .gnu => return 4, - else => return 8, - }, - else => {}, - }, - else => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - }, - .m68k => switch (c_type) { - .int, .uint, .long, .ulong => return 2, - else => {}, - }, - .wasm32, .wasm64 => switch (target.os.tag) { - .emscripten => switch (c_type) { - .longdouble => return 8, - else => {}, - }, - else => {}, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), - @as(u16, switch (target.cpu.arch) { - .x86_16, - .msp430, - => 2, - - .arc, - .arceb, - .csky, - .kalimba, - .microblaze, - .microblazeel, - .or1k, - .propeller, - .sh, - .sheb, - .xcore, - .xtensa, - .xtensaeb, - => 4, - - .amdgcn, - .arm, - .armeb, - .bpfeb, - .bpfel, - .hexagon, - .hppa, - .lanai, - .m68k, - .m88k, - .mips, - .mipsel, - .nvptx, - .nvptx64, - .s390x, - .sparc, - .thumb, - .thumbeb, - .x86, - => 8, - - .aarch64, - .aarch64_be, - .alpha, - .hppa64, - .kvx, - .loongarch32, - .loongarch64, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv32be, - .riscv64, - .riscv64be, - .sparc64, - .spirv32, - .spirv64, - .ve, - .wasm32, - .wasm64, - .x86_64, - => 16, - - .avr, - .ez80, - => unreachable, // Handled above. - }), - ); -} - pub fn cMaxIntAlignment(target: *const Target) u16 { return switch (target.cpu.arch) { .avr, @@ -3712,6 +3607,11 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { .xcore, => 4, + .x86 => switch (target.os.tag) { + else => 4, + .uefi, .windows => 8, + }, + .arm, .armeb, .hexagon, @@ -3730,7 +3630,6 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { .sparc, .thumb, .thumbeb, - .x86, .xtensa, .xtensaeb, => 8, @@ -3766,18 +3665,14 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention { return switch (target.cpu.arch) { .x86_64 => switch (target.os.tag) { - .windows, - .uefi, - => .{ .x86_64_win = .{} }, + .windows, .uefi => .{ .x86_64_win = .{} }, else => switch (target.abi) { .gnux32, .muslx32, .x32 => .{ .x86_64_x32 = .{} }, else => .{ .x86_64_sysv = .{} }, }, }, .x86 => switch (target.os.tag) { - .windows, - .uefi, - => .{ .x86_win = .{} }, + .windows, .uefi => if (target.isMinGW()) .{ .x86_mingw = .{} } else .{ .x86_win = .{} }, else => .{ .x86_sysv = .{} }, }, .x86_16 => .{ .x86_16_cdecl = .{} }, diff --git a/lib/std/bit_set.zig b/lib/std/bit_set.zig index b7920e20124d4e04f78662a14861ed7f9f6ae711..1a31e3b1a50b55cb8f26aa63789c1a04e9f6bc84 100644 --- a/lib/std/bit_set.zig +++ b/lib/std/bit_set.zig @@ -1707,8 +1707,6 @@ fn testStaticBitSet(comptime Set: type) !void { } test Integer { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - try testStaticBitSet(Integer(0)); try testStaticBitSet(Integer(1)); try testStaticBitSet(Integer(2)); diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index 33502074f661d86b2b6778361e85ab89172242d9..aa36b73ac3e36e51bea58c59fea780d1cc222ae8 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -1211,7 +1211,7 @@ pub const rsa = struct { 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40, }, - else => @compileError("unreachable"), + else => comptime unreachable, }; em_index -= hash_der.len; @memcpy(em[em_index..][0..hash_der.len], hash_der); diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index acf3a72e1fd2616a6074f896c3cf53da02364c48..54d1bd0dc8474d9eb299ca823864fdc9a1a001ea 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -6,9 +6,9 @@ const has_aesni = builtin.cpu.has(.x86, .aes); const has_avx = builtin.cpu.has(.x86, .avx); const has_armaes = builtin.cpu.has(.aarch64, .aes); // C backend doesn't currently support passing vectors to inline asm. -const impl = if (builtin.cpu.arch == .x86_64 and builtin.zig_backend != .stage2_c and has_aesni and has_avx) impl: { +const impl = if (builtin.cpu.arch == .x86_64 and has_aesni and has_avx) impl: { break :impl @import("aes/aesni.zig"); -} else if (builtin.cpu.arch == .aarch64 and builtin.zig_backend != .stage2_c and has_armaes) impl: { +} else if (builtin.cpu.arch == .aarch64 and (builtin.zig_backend != .stage2_c or !builtin.os.tag.isDarwin()) and has_armaes) impl: { break :impl @import("aes/armcrypto.zig"); } else impl: { break :impl @import("aes/soft.zig"); diff --git a/lib/std/crypto/aes_ocb.zig b/lib/std/crypto/aes_ocb.zig index 36e2aaa84cbb852ab0dc8b20ccf4aca8ecfea710..5c3af0615112822c58c892fa373150e23050dfcc 100644 --- a/lib/std/crypto/aes_ocb.zig +++ b/lib/std/crypto/aes_ocb.zig @@ -262,8 +262,6 @@ const hexToBytes = std.fmt.hexToBytes; const testing = std.testing; test "AesOcb test vector 1" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -281,8 +279,6 @@ test "AesOcb test vector 1" { } test "AesOcb test vector 2" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -303,8 +299,6 @@ test "AesOcb test vector 2" { } test "AesOcb test vector 3" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -329,8 +323,6 @@ test "AesOcb test vector 3" { } test "AesOcb test vector 4" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -356,8 +348,6 @@ test "AesOcb test vector 4" { } test "AesOcb in-place encryption-decryption" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig index b111b8e52a706b7b869a8091747934291912eff6..8977851b44ea04596ff686ec46fa576aa9b9693f 100644 --- a/lib/std/crypto/ecdsa.zig +++ b/lib/std/crypto/ecdsa.zig @@ -1,4 +1,3 @@ -const builtin = @import("builtin"); const std = @import("std"); const crypto = std.crypto; const fmt = std.fmt; @@ -415,8 +414,6 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { } test "Basic operations over EcdsaP384Sha384" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP384Sha384; const kp = Scheme.KeyPair.generate(io); @@ -432,8 +429,6 @@ test "Basic operations over EcdsaP384Sha384" { } test "Basic operations over Secp256k1" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaSecp256k1Sha256oSha256; const kp = Scheme.KeyPair.generate(io); @@ -449,8 +444,6 @@ test "Basic operations over Secp256k1" { } test "Basic operations over EcdsaP384Sha256" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); const kp = Scheme.KeyPair.generate(io); @@ -466,8 +459,6 @@ test "Basic operations over EcdsaP384Sha256" { } test "Verifying a existing signature with EcdsaP384Sha256" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); // zig fmt: off const sk_bytes = [_]u8{ @@ -503,8 +494,6 @@ test "Verifying a existing signature with EcdsaP384Sha256" { } test "Prehashed message operations" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP256Sha256; @@ -539,8 +528,6 @@ const TestVector = struct { }; test "Test vectors from Project Wycheproof - EcdsaP256Sha256 valid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // well-formed DER encoding -> expected valid .{ .key = "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", .msg = "313233343030", .sig = "304402202ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1802204cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76" }, @@ -711,8 +698,6 @@ test "Test vectors from Project Wycheproof - EcdsaP256Sha256 valid" { } test "Test vectors from Project Wycheproof - EcdsaP256Sha256 invalid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // S encoded with negative sign -> expected invalid .{ .key = "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", .msg = "313233343030", .sig = "304402202ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e180220b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db" }, @@ -1026,8 +1011,6 @@ test "Test vectors from Project Wycheproof - EcdsaP256Sha256 invalid" { } test "Test vectors from Project Wycheproof - EcdsaP384Sha384 valid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // canonical sign-bit padding on R; canonical sign-bit padding on S -> expected valid .{ .key = "0429bdb76d5fa741bfd70233cb3a66cc7d44beb3b0663d92a8136650478bcefb61ef182e155a54345a5e8e5e88f064e5bc9a525ab7f764dad3dae1468c2b419f3b62b9ba917d5e8c4fb1ec47404a3fc76474b2713081be9db4c00e043ada9fc4a3", .msg = "4d7367", .sig = "3066023100d7143a836608b25599a7f28dec6635494c2992ad1e2bbeecb7ef601a9c01746e710ce0d9c48accb38a79ede5b9638f3402310080f9e165e8c61035bf8aa7b5533960e46dd0e211c904a064edb6de41f797c0eae4e327612ee3f816f4157272bb4fabc9" }, @@ -1243,8 +1226,6 @@ test "Test vectors from Project Wycheproof - EcdsaP384Sha384 valid" { } test "Test vectors from Project Wycheproof - EcdsaP384Sha384 invalid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // S encoded with negative sign -> expected invalid .{ .key = "042da57dda1089276a543f9ffdac0bff0d976cad71eb7280e7d9bfd9fee4bdb2f20f47ff888274389772d98cc5752138aa4b6d054d69dcf3e25ec49df870715e34883b1836197d76f8ad962e78f6571bbc7407b0d6091f9e4d88f014274406174f", .msg = "313233343030", .sig = "3064023012b30abef6b5476fe6b612ae557c0425661e26b44b1bfe19daf2ca28e3113083ba8e4ae4cc45a0320abd3394f1c548d70230e7bf25603e2d07076ff30b7a2abec473da8b11c572b35fc631991d5de62ddca7525aaba89325dfd04fecc47bff426f82" }, @@ -1631,8 +1612,6 @@ fn tvTry(comptime Scheme: type, vector: TestVector) !void { } test "Sec1 encoding/decoding" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP384Sha384; const kp = Scheme.KeyPair.generate(io); diff --git a/lib/std/crypto/ff.zig b/lib/std/crypto/ff.zig index bf9584dfa3ad033652130705937972171370669c..c59dc92c61d66a457aabd11175f9ee0c5f83e582 100644 --- a/lib/std/crypto/ff.zig +++ b/lib/std/crypto/ff.zig @@ -966,8 +966,6 @@ const ct_unprotected = struct { }; test "finite field arithmetic" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const M = Modulus(256); const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233); var x = try M.Fe.fromPrimitive(u256, m, 80169837251094269539116136208111827396136208141182357733); @@ -1066,8 +1064,6 @@ test "finite field arithmetic" { } fn testCt(ct_: anytype) !void { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const l0: Limb = 0; const l1: Limb = 1; try testing.expectEqual(l1, ct_.select(true, l1, l0)); diff --git a/lib/std/crypto/pcurves/p384.zig b/lib/std/crypto/pcurves/p384.zig index 8bc0ec36f2d64e3c6d73e5d782b6df143c6a859f..7b97bf92b1b5ab138659e1348822d06885017fc5 100644 --- a/lib/std/crypto/pcurves/p384.zig +++ b/lib/std/crypto/pcurves/p384.zig @@ -56,7 +56,7 @@ pub const P384 = struct { } /// Create a point from serialized affine coordinates. - pub fn fromSerializedAffineCoordinates(xs: [48]u8, ys: [48]u8, endian: std.builtin.Endian) (NonCanonicalError || EncodingError)!P384 { + pub fn fromSerializedAffineCoordinates(xs: [48]u8, ys: [48]u8, endian: std.lang.Endian) (NonCanonicalError || EncodingError)!P384 { const x = try Fe.fromBytes(xs, endian); const y = try Fe.fromBytes(ys, endian); return fromAffineCoordinates(.{ .x = x, .y = y }); @@ -395,7 +395,7 @@ pub const P384 = struct { /// Multiply an elliptic curve point by a scalar. /// Return error.IdentityElement if the result is the identity element. - pub fn mul(p: P384, s_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mul(p: P384, s_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, false); @@ -407,7 +407,7 @@ pub const P384 = struct { /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulPublic(p: P384, s_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mulPublic(p: P384, s_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, true); @@ -419,7 +419,7 @@ pub const P384 = struct { /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulDoubleBasePublic(p1: P384, s1_: [48]u8, p2: P384, s2_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mulDoubleBasePublic(p1: P384, s1_: [48]u8, p2: P384, s2_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s1 = if (endian == .little) s1_ else Fe.orderSwap(s1_); const s2 = if (endian == .little) s2_ else Fe.orderSwap(s2_); try p1.rejectIdentity(); @@ -478,7 +478,5 @@ pub const AffineCoordinates = struct { }; test { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - _ = @import("tests/p384.zig"); } diff --git a/lib/std/crypto/pcurves/secp256k1.zig b/lib/std/crypto/pcurves/secp256k1.zig index 9ce8b944ebbffc071bcdd3be90fa47463525289e..3c36b9b2ed49d45dc1a13c0d9aab2a69d6dd3398 100644 --- a/lib/std/crypto/pcurves/secp256k1.zig +++ b/lib/std/crypto/pcurves/secp256k1.zig @@ -51,7 +51,7 @@ pub const Secp256k1 = struct { }; /// Compute r1 and r2 so that k = r1 + r2*lambda (mod L). - pub fn splitScalar(s: [32]u8, endian: std.builtin.Endian) NonCanonicalError!SplitScalar { + pub fn splitScalar(s: [32]u8, endian: std.lang.Endian) NonCanonicalError!SplitScalar { const b1_neg_s = comptime s: { var buf: [32]u8 = undefined; mem.writeInt(u256, &buf, 303414439467246543595250775667605759171, .little); @@ -109,7 +109,7 @@ pub const Secp256k1 = struct { } /// Create a point from serialized affine coordinates. - pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: std.builtin.Endian) (NonCanonicalError || EncodingError)!Secp256k1 { + pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: std.lang.Endian) (NonCanonicalError || EncodingError)!Secp256k1 { const x = try Fe.fromBytes(xs, endian); const y = try Fe.fromBytes(ys, endian); return fromAffineCoordinates(.{ .x = x, .y = y }); @@ -423,7 +423,7 @@ pub const Secp256k1 = struct { /// Multiply an elliptic curve point by a scalar. /// Return error.IdentityElement if the result is the identity element. - pub fn mul(p: Secp256k1, s_: [32]u8, endian: std.builtin.Endian) IdentityElementError!Secp256k1 { + pub fn mul(p: Secp256k1, s_: [32]u8, endian: std.lang.Endian) IdentityElementError!Secp256k1 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, false); @@ -435,7 +435,7 @@ pub const Secp256k1 = struct { /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulPublic(p: Secp256k1, s_: [32]u8, endian: std.builtin.Endian) (IdentityElementError || NonCanonicalError)!Secp256k1 { + pub fn mulPublic(p: Secp256k1, s_: [32]u8, endian: std.lang.Endian) (IdentityElementError || NonCanonicalError)!Secp256k1 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); const zero = comptime scalar.Scalar.zero.toBytes(.little); if (mem.eql(u8, &zero, &s)) { @@ -497,7 +497,7 @@ pub const Secp256k1 = struct { /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulDoubleBasePublic(p1: Secp256k1, s1_: [32]u8, p2: Secp256k1, s2_: [32]u8, endian: std.builtin.Endian) IdentityElementError!Secp256k1 { + pub fn mulDoubleBasePublic(p1: Secp256k1, s1_: [32]u8, p2: Secp256k1, s2_: [32]u8, endian: std.lang.Endian) IdentityElementError!Secp256k1 { const s1 = if (endian == .little) s1_ else Fe.orderSwap(s1_); const s2 = if (endian == .little) s2_ else Fe.orderSwap(s2_); try p1.rejectIdentity(); @@ -556,7 +556,5 @@ pub const AffineCoordinates = struct { }; test { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - _ = @import("tests/secp256k1.zig"); } diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 36be9fe60e0ebe084ab2e045702bc91628ff9bf6..ab90b9b2c27e374ef56148334eb83fcc13d6ba75 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -2020,6 +2020,8 @@ const signal_ucontext_t = switch (native_os) { .mips64el, .or1k, .s390x, + .sh, + .sheb, .x86, .x86_64, .xtensa, diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 7cdc44269cdc95b492eb8ac718a53d7fe721af55..0c3dba4a7a95ff9a68f8d9f64d082c35565134a7 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1082,8 +1082,6 @@ test "float.libc.sanity" { } test "union" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const TU = union(enum) { float: f32, int: u32, diff --git a/lib/std/fmt/float.zig b/lib/std/fmt/float.zig index 25bf97f22ae52df136be9dbbdeab2e0fdedfdc18..e055959825832e1889d6d2c0fb6cfd131d06d50b 100644 --- a/lib/std/fmt/float.zig +++ b/lib/std/fmt/float.zig @@ -65,7 +65,7 @@ pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 { const DT = if (@bitSizeOf(T) <= 64) u64 else u128; const tables = switch (DT) { - u64 => if (@import("builtin").mode == .small) &Backend64_TablesSmall else &Backend64_TablesFull, + u64 => if (builtin.mode == .small) &Backend64_TablesSmall else &Backend64_TablesFull, u128 => &Backend128_Tables, else => unreachable, }; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index fc613ccdaa313d46dab643f849149293f422a9a5..e9c2d5f8f8e167b7556ec5eaec20d994cc2f5d73 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -2205,7 +2205,7 @@ test "'.' and '..' in absolute functions" { } test "chmod" { - if (native_os == .windows or native_os == .wasi) return; + if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; const io = testing.io; @@ -2228,8 +2228,7 @@ test "chmod" { } test "change ownership" { - if (native_os == .windows or native_os == .wasi) - return error.SkipZigTest; + if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; const io = testing.io; diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 3964ad5f946f899a51cbfdefb38cb42d2973b74d..1cb8e93092ec55534810432e78e896d88ffa881a 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -225,7 +225,7 @@ fn testHashDeepRecursive(key: anytype) u64 { test "typeContainsSlice" { comptime { - try testing.expect(!typeContainsSlice(std.meta.Tag(std.builtin.Type))); + try testing.expect(!typeContainsSlice(std.meta.Tag(std.lang.Type))); try testing.expect(typeContainsSlice([]const u8)); try testing.expect(!typeContainsSlice(u8)); diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig index 27f2701443cc919a9cd2686165ecc8ae087ae002..72c8bff280548134abcb34a71857c7c101683dae 100644 --- a/lib/std/hash/xxhash.zig +++ b/lib/std/hash/xxhash.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const mem = std.mem; const expectEqual = std.testing.expectEqual; @@ -788,7 +787,6 @@ fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) } test "xxhash3" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const H = XxHash3; // Non-Seeded Tests try testExpect(H, 0, "", 0x2d06800538d394c2); @@ -820,7 +818,6 @@ test "xxhash3" { } test "xxhash3 smhasher" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const Test = struct { fn do() !void { try expectEqual(verify.smhasher(XxHash3.hash), 0x9a636405); @@ -832,7 +829,6 @@ test "xxhash3 smhasher" { } test "xxhash3 iterative api" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const Test = struct { fn do() !void { try verify.iterativeApi(XxHash3); diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig index a6562bc5ea1ab479963b308beae24fb303d98c6d..b11f7e4a0dee9413d8ca5a798492c48f0ba5dde1 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -1518,7 +1518,7 @@ fn Custom( self.available = 0; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// header type to facilitate fancy debug printing for this type. fn dbHelper(self: *Self, hdr: *Header, entry: *Entry) void { _ = self; diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig index 39f2063f65d7c1b175ce0750e9512abaee3f2c20..e7a37daa68de6751d5762b7639e25bd1401a37c0 100644 --- a/lib/std/http/test.zig +++ b/lib/std/http/test.zig @@ -1,5 +1,4 @@ const builtin = @import("builtin"); -const native_endian = builtin.cpu.arch.endian(); const std = @import("std"); const http = std.http; @@ -34,7 +33,6 @@ test "content length reader state update" { } test "trailers" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -121,7 +119,6 @@ test "trailers" { } test "HTTP server handles a chunked transfer coding request" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -190,7 +187,6 @@ test "HTTP server handles a chunked transfer coding request" { } test "echo content server" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -281,12 +277,11 @@ test "echo content server" { } test "Server.Request.respondStreaming non-chunked, unknown content-length" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; - if (builtin.os.tag == .windows) { + if (builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/21457 return error.SkipZigTest; } @@ -360,7 +355,6 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" { } test "receiving arbitrary http headers from the client" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -426,16 +420,10 @@ test "receiving arbitrary http headers from the client" { } test "general client/server API coverage" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; - if (builtin.os.tag == .windows) { - // This test was never passing on Windows. - return error.SkipZigTest; - } - const test_server = try createTestServer(io, struct { fn run(test_server: *TestServer) anyerror!void { const net_server = &test_server.net_server; @@ -922,7 +910,6 @@ test "general client/server API coverage" { } test "Server streams both reading and writing" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -1162,10 +1149,6 @@ const TestServer = struct { fn createTestServer(io: Io, S: type) !*TestServer { if (builtin.single_threaded) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and native_endian == .big) { - // https://github.com/ziglang/zig/issues/13782 - return error.SkipZigTest; - } const address = try net.IpAddress.parse("127.0.0.1", 0); @@ -1192,7 +1175,6 @@ fn createTestServer(io: Io, S: type) !*TestServer { } test "redirect to different connection" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -1280,7 +1262,6 @@ test "redirect to different connection" { } test "boot failed connections from the pool" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; diff --git a/lib/std/lang.zig b/lib/std/lang.zig index 2f0868c39331456b03f055cafd8546f19ac51b07..f15f26d9f9330431846e52ff9d98b131fbc666e2 100644 --- a/lib/std/lang.zig +++ b/lib/std/lang.zig @@ -214,6 +214,7 @@ pub const CallingConvention = union(enum(u8)) { // Calling conventions for the `x86` architecture. x86_sysv: X86RegparmOptions, x86_win: X86RegparmOptions, + x86_mingw: X86RegparmOptions, x86_stdcall: X86RegparmOptions, x86_fastcall: CommonOptions, x86_thiscall: CommonOptions, diff --git a/lib/std/math.zig b/lib/std/math.zig index b43bc8f5981ec9083596a17ac90df631fc31d33f..27d5e0d584dca43e838d31eabec11ca2134045d9 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -75,7 +75,7 @@ pub const snan = float.snan; /// /// NaN values are never considered equal to any value. pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { - assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); + comptime assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); assert(tolerance >= 0); // Fast path for equal values (and signed zeros and infinites). @@ -103,7 +103,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { /// /// NaN values are never considered equal to any value. pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool { - assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); + comptime assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); assert(tolerance > 0); // Fast path for equal values (and signed zeros and infinites). @@ -461,7 +461,7 @@ pub fn wrap(x: anytype, r: anytype) @TypeOf(x) { } } test wrap { - if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) { + if (builtin.os.tag == .windows and builtin.cpu.arch == .x86 and builtin.abi == .msvc) { // https://codeberg.org/ziglang/zig/issues/35520 return error.SkipZigTest; } @@ -1385,7 +1385,8 @@ pub fn lerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) { } test lerp { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/17884 + if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isX86()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime builtin.cpu.has(.x86, .fma)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/17884 try testing.expectEqual(@as(f64, 75), lerp(50, 100, 0.5)); diff --git a/lib/std/math/acos.zig b/lib/std/math/acos.zig index 285190227c75b5780d3b2678656272b2e01d068a..d79c36182e0aa6ebd784c45f56c0232905a9c1a2 100644 --- a/lib/std/math/acos.zig +++ b/lib/std/math/acos.zig @@ -337,8 +337,6 @@ fn acosBinary128(x: f128) f128 { } test "acosBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.92p0, acosBinary16(0x0p+0), math.floatEpsAt(f16, 0x1.92p0)); try testing.expectApproxEqAbs(0x1.92p1, acosBinary16(-0x1p+0), math.floatEpsAt(f16, 0x1.92p1)); try testing.expectEqual(0x0p+0, acosBinary16(0x1p+0)); @@ -350,8 +348,6 @@ test "acosBinary16.special" { } test "acosBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.834p0, acosBinary16(0x1.db4p-5), math.floatEpsAt(f16, 0x1.834p0)); try testing.expectApproxEqAbs(0x1.d48p0, acosBinary16(-0x1.068p-2), math.floatEpsAt(f16, 0x1.d48p0)); try testing.expectApproxEqAbs(0x1.b7cp0, acosBinary16(-0x1.2c4p-3), math.floatEpsAt(f16, 0x1.b7cp0)); diff --git a/lib/std/math/asin.zig b/lib/std/math/asin.zig index 68efd182aaf93db9ba5824cd76be55854c5c5f40..dfd3f063954c68d25230993b0875873273eb9ff8 100644 --- a/lib/std/math/asin.zig +++ b/lib/std/math/asin.zig @@ -326,8 +326,6 @@ fn asinBinary128(x: f128) f128 { } test "asinBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.92p0, asinBinary16(0x1p+0), math.floatEpsAt(f16, 0x1.92p0)); try testing.expectApproxEqAbs(-0x1.92p0, asinBinary16(-0x1p+0), math.floatEpsAt(f16, -0x1.92p0)); try testing.expectEqual(0x0p+0, asinBinary16(0x0p+0)); @@ -340,8 +338,6 @@ test "asinBinary16.special" { } test "asinBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(-0x1.e4cp-6, asinBinary16(-0x1.e4cp-6), math.floatEpsAt(f16, -0x1.e4cp-6)); try testing.expectApproxEqAbs(0x1.2a8p0, asinBinary16(0x1.d68p-1), math.floatEpsAt(f16, 0x1.2a8p0)); try testing.expectApproxEqAbs(-0x1.eep-1, asinBinary16(-0x1.a4cp-1), math.floatEpsAt(f16, -0x1.eep-1)); diff --git a/lib/std/math/atan.zig b/lib/std/math/atan.zig index 2d55b8bc1343d95f6671a96636d55b2b4a269c8e..75dab1b0c19732b229000d62634e7944491db254 100644 --- a/lib/std/math/atan.zig +++ b/lib/std/math/atan.zig @@ -481,8 +481,6 @@ fn atanBinary128(x: f128) f128 { } test "atanBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectEqual(0x0p+0, atanBinary16(0x0p+0)); try testing.expectEqual(-0x0p+0, atanBinary16(-0x0p+0)); try testing.expectApproxEqAbs(0x1.92p-1, atanBinary16(0x1p+0), math.floatEpsAt(f16, 0x1.92p-1)); @@ -493,8 +491,6 @@ test "atanBinary16.special" { } test "atanBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(-0x1.74cp-2, atanBinary16(-0x1.864p-2), math.floatEpsAt(f16, -0x1.74cp-2)); try testing.expectApproxEqAbs(-0x1.374p0, atanBinary16(-0x1.59cp1), math.floatEpsAt(f16, -0x1.374p0)); try testing.expectApproxEqAbs(-0x1.11cp0, atanBinary16(-0x1.d2cp0), math.floatEpsAt(f16, -0x1.11cp0)); diff --git a/lib/std/math/atan2.zig b/lib/std/math/atan2.zig index f0c8aa0792046a94b900fba216dde87724ec8e1c..7c7bb4bb78e34d8d3b2c3403eba2e63d3ed1d3ce 100644 --- a/lib/std/math/atan2.zig +++ b/lib/std/math/atan2.zig @@ -252,8 +252,8 @@ test "atan2_32.special" { try expect(math.isNan(atan2_32(1.0, math.nan(f32)))); try expect(math.isNan(atan2_32(math.nan(f32), 1.0))); - try expect(atan2_32(0.0, 5.0) == 0.0); - try expect(atan2_32(-0.0, 5.0) == -0.0); + try expect(math.isPositiveZero(atan2_32(0.0, 5.0))); + try expect(math.isNegativeZero(atan2_32(-0.0, 5.0))); try expect(math.approxEqAbs(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); //expect(math.approxEqAbs(f32, atan2_32(-0.0, -5.0), -math.pi, .{.rel=0,.abs=epsilon})); TODO support negative zero? try expect(math.approxEqAbs(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); @@ -276,8 +276,8 @@ test "atan2_64.special" { try expect(math.isNan(atan2_64(1.0, math.nan(f64)))); try expect(math.isNan(atan2_64(math.nan(f64), 1.0))); - try expect(atan2_64(0.0, 5.0) == 0.0); - try expect(atan2_64(-0.0, 5.0) == -0.0); + try expect(math.isPositiveZero(atan2_64(0.0, 5.0))); + try expect(math.isNegativeZero(atan2_64(-0.0, 5.0))); try expect(math.approxEqAbs(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); //expect(math.approxEqAbs(f64, atan2_64(-0.0, -5.0), -math.pi, .{.rel=0,.abs=epsilon})); TODO support negative zero? try expect(math.approxEqAbs(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 485ae4918cce7545119b5b014f7c8133656aaf0b..271041e761a1d6f089c7733aa2964913c771dc0d 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -1,5 +1,4 @@ const std = @import("../../std.zig"); -const builtin = @import("builtin"); const mem = std.mem; const testing = std.testing; const Managed = std.math.big.int.Managed; @@ -276,8 +275,6 @@ fn setFloat(comptime Float: type) !void { try expectNormalized(1 << 10, res.toConst()); } test setFloat { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - try setFloat(f16); try setFloat(f32); try setFloat(f64); @@ -484,7 +481,6 @@ fn toFloat(comptime Float: type) !void { ); } test toFloat { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; try toFloat(f16); try toFloat(f32); try toFloat(f64); @@ -1391,8 +1387,6 @@ test "mul multi-single" { } test "mul multi-multi" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var op1: u256 = 0x998888efefefefefefefef; var op2: u256 = 0x333000abababababababab; _ = .{ &op1, &op2 }; @@ -1514,8 +1508,6 @@ test "mulWrap single-single signed" { } test "mulWrap multi-multi unsigned" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var op1: u256 = 0x998888efefefefefefefef; var op2: u256 = 0x333000abababababababab; _ = .{ &op1, &op2 }; @@ -1533,11 +1525,6 @@ test "mulWrap multi-multi unsigned" { } test "mulWrap multi-multi signed" { - switch (builtin.zig_backend) { - .stage2_c => return error.SkipZigTest, - else => {}, - } - var a = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb) - 1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb)); @@ -1744,8 +1731,6 @@ test "div q=0 alias" { } test "div multi-multi q < r" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const op1 = 0x1ffffffff0078f432; const op2 = 0x1ffffffff01000000; var a = try Managed.initSet(testing.allocator, op1); @@ -2166,8 +2151,6 @@ test "div ceil multi-limb" { } test "div multi-multi with rem" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x99990000111122223333); @@ -2184,8 +2167,6 @@ test "div multi-multi with rem" { } test "div multi-multi no rem" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeedb4fec200ee3a4286361); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x99990000111122223333); @@ -2202,8 +2183,6 @@ test "div multi-multi no rem" { } test "div multi-multi (2 branch)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x866666665555555588888887777777761111111111111111); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x86666666555555554444444433333333); @@ -2220,8 +2199,6 @@ test "div multi-multi (2 branch)" { } test "div multi-multi (3.1/3.3 branch)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x1111111111111111111111111111111111111111171); @@ -2238,8 +2215,6 @@ test "div multi-multi (3.1/3.3 branch)" { } test "div multi-single zero-limb trailing" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x60000000000000000000000000000000000000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x10000000000000000); @@ -2258,8 +2233,6 @@ test "div multi-single zero-limb trailing" { } test "div multi-multi zero-limb trailing (with rem)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); @@ -2279,8 +2252,6 @@ test "div multi-multi zero-limb trailing (with rem)" { } test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8666666655555555888888877777777611111111111111110000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); @@ -2300,8 +2271,6 @@ test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count } test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x866666665555555544444444333333330000000000000000); @@ -2832,10 +2801,6 @@ test "bitNotWrap signed multi" { } test "bitNotWrap more than two limbs" { - // This test requires int sizes greater than 128 bits. - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - var a = try Managed.initSet(testing.allocator, maxInt(Limb)); defer a.deinit(); @@ -3179,8 +3144,6 @@ test "gcd non-one large" { } test "gcd large multi-limb result" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x12345671234567123456712345671234567123456712345671234567); @@ -3431,7 +3394,7 @@ test "big int conversion read/write twos complement" { var buffer1 = try testing.allocator.alloc(u8, 64); defer testing.allocator.free(buffer1); - const endians = [_]std.builtin.Endian{ .little, .big }; + const endians = [_]std.lang.Endian{ .little, .big }; const abi_size = 64; for (endians) |endian| { diff --git a/lib/std/math/gamma.zig b/lib/std/math/gamma.zig index ce9a2b07f91b2cc5e5909069813d28bd4b7e9ce6..fed7e87ceef250eb92b67d43973289635c54d06c 100644 --- a/lib/std/math/gamma.zig +++ b/lib/std/math/gamma.zig @@ -263,8 +263,6 @@ test gamma { } test "gamma.special" { - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 - inline for (&.{ f32, f64 }) |T| { try expect(std.math.isNan(gamma(T, -std.math.nan(T)))); try expect(std.math.isNan(gamma(T, std.math.nan(T)))); diff --git a/lib/std/math/hypot.zig b/lib/std/math/hypot.zig index ef3fc97af3d3ea21b7cb525c616d248ffc20da7d..99da74c335c342a277778f79bafe53e7fb2d7766 100644 --- a/lib/std/math/hypot.zig +++ b/lib/std/math/hypot.zig @@ -1,4 +1,3 @@ -const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; @@ -93,14 +92,10 @@ const hypot_test_cases = .{ }; test hypot { - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 try expect(hypot(0.3, 0.4) == 0.5); } test "hypot.correct" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 - inline for (.{ f16, f32, f64, f128 }) |T| { inline for (hypot_test_cases) |v| { const a: T, const b: T, const c: T = v; @@ -110,9 +105,6 @@ test "hypot.correct" { } test "hypot.precise" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 - inline for (.{ f16, f32, f64 }) |T| { // f128 seems to be 5 ulp inline for (hypot_test_cases) |v| { const a: T, const b: T, const c: T = v; @@ -122,7 +114,6 @@ test "hypot.precise" { } test "hypot.special" { - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 @setEvalBranchQuota(2000); inline for (.{ f16, f32, f64, f128 }) |T| { try expect(math.isNan(hypot(nan(T), 0.0))); diff --git a/lib/std/math/isnan.zig b/lib/std/math/isnan.zig index bf2af9be1db7472aaceae82c3d052e606ce454b7..cfbe172ecdbe22890c9e928103b328f7fe23a256 100644 --- a/lib/std/math/isnan.zig +++ b/lib/std/math/isnan.zig @@ -27,13 +27,6 @@ test isNan { } test isSignalNan { - if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; - - if (builtin.os.tag == .windows) { - // https://codeberg.org/ziglang/zig/issues/35519 - return error.SkipZigTest; - } - inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { // TODO: Signalling NaN values get converted to quiet NaN values in // some cases where they shouldn't such that this can fail. @@ -43,6 +36,7 @@ test isSignalNan { builtin.cpu.arch != .hexagon and !builtin.cpu.arch.isMIPS32() and !builtin.cpu.arch.isPowerPC() and + !(builtin.cpu.arch.isX86() and builtin.os.tag == .windows and builtin.abi == .msvc) and // https://codeberg.org/ziglang/zig/issues/35519 builtin.zig_backend != .stage2_c) { try expect(isSignalNan(math.snan(T))); diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig index a46948cac54dddf2dd7a822a68188f219086a9af..0dc5b2a8be90cd88276ec344c9de51a492b6430a 100644 --- a/lib/std/math/log10.zig +++ b/lib/std/math/log10.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const testing = std.testing; /// Returns the base-10 logarithm of x. @@ -135,10 +134,6 @@ inline fn less_than_5(x: u32) u32 { } test log10_int { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - inline for ( .{ u8, u16, u32, u64, u128, u256, u512 }, .{ 2, 4, 9, 19, 38, 77, 154 }, diff --git a/lib/std/math/modf.zig b/lib/std/math/modf.zig index 15515cde204a727d0191db34ace8adc68feb39e3..ea0433906958619572ad604d113f149c6fada392 100644 --- a/lib/std/math/modf.zig +++ b/lib/std/math/modf.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -85,9 +84,6 @@ fn ModfTests(comptime T: type) type { try expectApproxEqAbs(expected_c, r.fpart, epsilon); } test "vector" { - if (builtin.os.tag.isDarwin() and builtin.cpu.arch == .aarch64) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194256 - const widths = [_]comptime_int{ 1, 2, 3, 4, 8, 16 }; inline for (widths) |len| { diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig index 115aaa26eb056e31c423695cd2a2cde79050d0a1..36a933e641ce35985523b25bb403f234143c20bc 100644 --- a/lib/std/math/signbit.zig +++ b/lib/std/math/signbit.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 8353c0ca8e209dd1516371926e0fbfd00f874ded..9529f73b93586014b6338eef2ecd780461b9cd37 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -4780,62 +4780,47 @@ pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize { pub fn doNotOptimizeAway(val: anytype) void { if (@inComptime()) return; + if (builtin.zig_backend == .stage2_c and builtin.abi == .msvc) { + _ = @atomicRmw(*const anyopaque, @as(*volatile *const anyopaque, &struct { + var escape: *const anyopaque = undefined; + }.escape), .Xchg, &val, .acq_rel); // TODO: syncscope("singlethreaded") + return; + } + const max_gp_register_bits = @bitSizeOf(c_long); - const t = @typeInfo(@TypeOf(val)); - switch (t) { + switch (@typeInfo(@TypeOf(val))) { .void, .null, .comptime_int, .comptime_float => return, .@"enum" => doNotOptimizeAway(@backingInt(val)), .bool => doNotOptimizeAway(@intFromBool(val)), - .int => { - const bits = t.int.bits; - if (bits <= max_gp_register_bits and builtin.zig_backend != .stage2_c) { - const val2 = @as( - @Int(t.int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))), - val, - ); - asm volatile ("" - : - : [_] "r" (val2), - ); - } else doNotOptimizeAway(&val); - }, - .float => { - if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) { - asm volatile ("" - : - : [_] "rm" (val), - ); - } else doNotOptimizeAway(&val); - }, - .pointer => { - if (builtin.zig_backend == .stage2_c) { - doNotOptimizeAwayC(val); - } else { - asm volatile ("" - : - : [_] "m" (val), - : .{ .memory = true }); - } - }, - .array => { - if (t.array.len * @sizeOf(t.array.child) <= 64) { - for (val) |v| doNotOptimizeAway(v); - } else doNotOptimizeAway(&val); + .int => |int| if (int.bits <= max_gp_register_bits) { + const val2 = @as( + @Int(int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, int.bits))), + val, + ); + asm volatile ("" + : + : [_] "r" (val2), + ); + } else doNotOptimizeAway(&val), + .float => |float| switch (float.bits) { + else => comptime unreachable, + 16, 80, 128 => doNotOptimizeAway(&val), + 32, 64 => asm volatile ("" + : + : [_] "rm" (val), + ), }, + .pointer => asm volatile ("" + : + : [_] "m" (val), + : .{ .memory = true }), + .array => |array| if (array.len * @sizeOf(array.child) <= 64) { + for (val) |v| doNotOptimizeAway(v); + } else doNotOptimizeAway(&val), else => doNotOptimizeAway(&val), } } -/// .stage2_c doesn't support asm blocks yet, so use volatile stores instead -var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined; -fn doNotOptimizeAwayC(ptr: anytype) void { - const dest = @as(*volatile u8, @ptrCast(&deopt_target)); - for (asBytes(ptr)) |b| { - dest.* = b; - } - dest.* = 0; -} - test doNotOptimizeAway { comptime doNotOptimizeAway("test"); @@ -4994,12 +4979,9 @@ pub fn alignInSlice(slice: anytype, comptime new_alignment: usize) ?AlignedSlice } test "read/write(Var)PackedInt" { - switch (builtin.cpu.arch) { - // This test generates too much code to execute on WASI. - // LLVM backend fails with "too many locals: locals exceed maximum" - .wasm32, .wasm64 => return error.SkipZigTest, - else => {}, - } + // This test generates too much code to execute on WASI. + // LLVM backend fails with "too many locals: locals exceed maximum" + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; const foreign_endian: Endian = if (native_endian == .big) .little else .big; const expect = std.testing.expect; diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index a10f261e31ef8d4f47a976eebb3f637c199f835f..ce6265655eb690499577bc7fbd29c19eab375854 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -163,7 +163,7 @@ pub fn MultiArrayList(comptime T: type) type { }; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// child field order and entry type to facilitate fancy debug printing for this type. fn dbHelper(self: *Slice, child: *Elem, field: *Field, entry: *Entry) void { _ = self; @@ -681,7 +681,7 @@ pub fn MultiArrayList(comptime T: type) type { } break :entry @Struct(.@"extern", null, &entry_field_names, &entry_field_types, &entry_field_attrs); }; - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// child field order and entry type to facilitate fancy debug printing for this type. fn dbHelper(self: *Self, child: *Elem, field: *Field, entry: *Entry) void { _ = self; diff --git a/lib/std/os/linux/IoUring/test.zig b/lib/std/os/linux/IoUring/test.zig index 40429fbaab1cb7fb35a90427c69c2640ad907ed6..891ce5a397f61e2b6c655192d714e35d21f7e32c 100644 --- a/lib/std/os/linux/IoUring/test.zig +++ b/lib/std/os/linux/IoUring/test.zig @@ -1836,8 +1836,6 @@ test "accept/connect/send_zc/recv" { } test "accept_direct" { - if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30854 - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); var ring = IoUring.init(1, 0) catch |err| switch (err) { @@ -1925,11 +1923,6 @@ test "accept_direct" { test "accept_multishot_direct" { try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - if (builtin.cpu.arch == .riscv64) { - // https://github.com/ziglang/zig/issues/25734 - return error.SkipZigTest; - } - var ring = IoUring.init(1, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index a49c1d48bedd05331da4a7a25c6f1006797aa251..431097feccf104eba84a3f347fac6fe29ae1eb57 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -154,7 +154,7 @@ pub const restore = restore_rt; pub fn restore_rt() callconv(.naked) noreturn { switch (builtin.zig_backend) { .stage2_c => asm volatile ( - \\ mov x8, %[number] + \\ mov w8, %[number] \\ svc #0 : : [number] "i" (@backingInt(SYS.rt_sigreturn)), diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index 9b9ca0cd0327c93c1260128f42a497e8d96a3094..3c44beeb8df7bb5d7f0d7d7fb13f3c35c840da01 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -174,19 +174,35 @@ pub fn clone() callconv(.naked) u64 { } pub fn restore() callconv(.naked) noreturn { - asm volatile ( - \\svc 0 - : - : [number] "{r1}" (@backingInt(SYS.sigreturn)), - ); + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\lghi %%r1, %[number] + \\svc 0 + : + : [number] "K" (@backingInt(SYS.sigreturn)), + ), + else => asm volatile ( + \\svc 0 + : + : [number] "{r1}" (@backingInt(SYS.sigreturn)), + ), + } } pub fn restore_rt() callconv(.naked) noreturn { - asm volatile ( - \\svc 0 - : - : [number] "{r1}" (@backingInt(SYS.rt_sigreturn)), - ); + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\lghi %%r1, %[number] + \\svc 0 + : + : [number] "K" (@backingInt(SYS.rt_sigreturn)), + ), + else => asm volatile ( + \\svc 0 + : + : [number] "{r1}" (@backingInt(SYS.rt_sigreturn)), + ), + } } pub const time_t = i64; diff --git a/lib/std/testing/Smith.zig b/lib/std/testing/Smith.zig index 7e3235fe0e5ffd1163a2cc7bf46f7583eb0a06ae..a60a9802391078fe6ca400fb4409216bd73ff345 100644 --- a/lib/std/testing/Smith.zig +++ b/lib/std/testing/Smith.zig @@ -708,7 +708,7 @@ fn constructInput(comptime values: []const union(enum) { } test value { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = struct { v: void = {}, diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index d0e86c80ac3baa8c9504095b8200b546789a39b2..8b9e87f8139f951b7abc475c5afb3035176cb209 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -17,7 +17,7 @@ gpa: Allocator, strip: bool, source_filename: String, -data_layout: String, +data_layout: DataLayout, target_triple: String, module_asm: std.ArrayList(u8), @@ -87,6 +87,455 @@ pub const Options = struct { triple: []const u8 = &.{}, }; +pub const DataLayout = struct { + endian: ?std.lang.Endian, + int_specs: PrimitiveSpec.Map, + float_specs: PrimitiveSpec.Map, + vector_specs: PrimitiveSpec.Map, + pointer_specs: PointerSpec.Map, + string_repr: String, + + const PrimitiveSpec = packed struct(u32) { + bit_width: BitWidth, + abi_align: Alignment, + pref_align: Alignment, + + const BitWidth = u20; + + const Map = std.array_hash_map.Custom(PrimitiveSpec, void, Context, false); + + const Context = struct { + pub fn hash(_: Context, spec: PrimitiveSpec) u32 { + return std.hash.int(spec.bit_width); + } + + pub fn eql(_: Context, lhs_spec: PrimitiveSpec, rhs_spec: PrimitiveSpec, _: usize) bool { + return lhs_spec.bit_width == rhs_spec.bit_width; + } + }; + }; + + const PointerSpec = struct { + bit_width: BitWidth, + index_bit_width: BitWidth, + flags: packed struct(u32) { + abi_align: Alignment, + pref_align: Alignment, + has_unstable_repr: bool, + has_external_state: bool, + null_ptr_repr: NullPtrRepr, + unused: u17 = 0, + }, + addr_space_name: String, + + const BitWidth = u32; + + const NullPtrRepr = enum(u1) { all_zeros, all_ones }; + + const Map = std.array_hash_map.Auto(AddrSpace, PointerSpec); + }; + + pub fn stringForTarget(target: *const std.Target) []const u8 { + // These data layouts should match Clang. + return switch (target.cpu.arch) { + .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32", + .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32", + .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048", + .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64", + .aarch64 => if (target.ofmt == .macho) + if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else if (target.abi == .ilp32) + "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" + else + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", + .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", + .arm => if (target.ofmt == .macho) + "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .armeb, .thumbeb => if (target.ofmt == .macho) + "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .thumb => if (target.ofmt == .macho) + "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8", + .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16", + .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + .mips64 => switch (target.abi) { + .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + }, + .mips64el => switch (target.abi) { + .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + }, + .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16", + .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32", + .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32", + .powerpc64 => switch (target.os.tag) { + .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", + .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64", + else => "E-m:e-Fn32-i64:64-i128:128-n32:64", + }, + .powerpc64le => if (target.os.tag == .linux) + "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" + else + "e-m:e-Fn32-i64:64-i128:128-n32:64", + .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", + .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", + .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9", + .riscv32 => if (target.cpu.has(.riscv, .e)) + "e-m:e-p:32:32-i64:64-n32-S32" + else + "e-m:e-p:32:32-i64:64-n32-S128", + .riscv32be => if (target.cpu.has(.riscv, .e)) + "E-m:e-p:32:32-i64:64-n32-S32" + else + "E-m:e-p:32:32-i64:64-n32-S128", + .riscv64 => if (target.cpu.has(.riscv, .e)) + "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64" + else + "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .riscv64be => if (target.cpu.has(.riscv, .e)) + "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64" + else + "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64", + .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128", + .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64", + .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) { + .gnu => if (target.ofmt == .coff) + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32", + else => blk: { + const msvc = switch (target.abi) { + .none, .msvc => true, + else => false, + }; + + break :blk if (target.ofmt == .coff) + if (msvc) + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" + else + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + else if (msvc) + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"; + }, + } else if (target.ofmt == .macho) + "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", + .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho) + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + else switch (target.abi) { + .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff) + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + else + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + }, + .spirv32 => switch (target.os.tag) { + .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + }, + .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + .wasm32 => if (target.os.tag == .emscripten) + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" + else + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", + .wasm64 => if (target.os.tag == .emscripten) + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" + else + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", + .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64", + .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32", + .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128", + .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32", + + .alpha, + .arceb, + .ez80, + .hppa, + .hppa64, + .kalimba, + .kvx, + .m88k, + .microblaze, + .microblazeel, + .or1k, + .propeller, + .sh, + .sheb, + .x86_16, + .xtensaeb, + => unreachable, + }; + } + + const default_int_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 8, .abi_align = .fromByteUnits(1), .pref_align = .fromByteUnits(1) }, // i8:8:8 + .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // i16:16:16 + .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // i32:32:32 + .{ .bit_width = 64, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(8) }, // i64:32:64 + }; + const default_float_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // f16:16:16 + .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // f32:32:32 + .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // f64:64:64 + .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // f128:128:128 + }; + const default_vector_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // v64:64:64 + .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // v128:128:128 + }; + + pub fn parseString(string_repr: String, builder: *Builder) Allocator.Error!DataLayout { + const gpa = builder.gpa; + + var int_specs: PrimitiveSpec.Map = .empty; + defer int_specs.deinit(gpa); + var float_specs: PrimitiveSpec.Map = .empty; + defer float_specs.deinit(gpa); + var vector_specs: PrimitiveSpec.Map = .empty; + defer vector_specs.deinit(gpa); + var pointer_specs: PointerSpec.Map = .empty; + defer pointer_specs.deinit(gpa); + var non_integral_addr_spaces: std.ArrayList(AddrSpace) = .empty; + defer non_integral_addr_spaces.deinit(gpa); + + try int_specs.ensureTotalCapacity(gpa, default_int_specs.len); + for (default_int_specs) |int_spec| int_specs.putAssumeCapacityNoClobber(int_spec, {}); + try float_specs.ensureTotalCapacity(gpa, default_float_specs.len); + for (default_float_specs) |float_spec| float_specs.putAssumeCapacityNoClobber(float_spec, {}); + try vector_specs.ensureTotalCapacity(gpa, default_vector_specs.len); + for (default_vector_specs) |vector_spec| vector_specs.putAssumeCapacityNoClobber(vector_spec, {}); + try pointer_specs.putNoClobber(gpa, .default, comptime .{ + .bit_width = 64, + .index_bit_width = 64, + .flags = .{ + .abi_align = .fromByteUnits(8), + .pref_align = .fromByteUnits(8), + .has_unstable_repr = false, + .has_external_state = false, + .null_ptr_repr = .all_zeros, + }, + .addr_space_name = .none, + }); + + var endian: ?std.lang.Endian = null; + var spec_it = std.mem.splitScalar(u8, string_repr.slice(builder).?, '-'); + while (spec_it.next()) |spec| switch (spec[0]) { + else => {}, + 'E' => { + assert(spec.len == 1); + assert(endian == null); + endian = .big; + }, + 'e' => { + assert(spec.len == 1); + assert(endian == null); + endian = .little; + }, + 'p' => { + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + + const first = field_it.first(); + var has_unstable_repr = false; + var has_external_state = false; + var null_ptr_repr: ?PointerSpec.NullPtrRepr = null; + var addr_space_name: String = .none; + const addr_space = for (first, 0..) |flag, as_start| switch (flag) { + 'u' => has_unstable_repr = true, + 'e' => has_external_state = true, + 'z' => { + assert(null_ptr_repr == null); + null_ptr_repr = .all_zeros; + }, + 'o' => { + assert(null_ptr_repr == null); + null_ptr_repr = .all_ones; + }, + else => { + if (first[first.len - ")".len] != ')') break first[as_start..]; + const name_start = std.mem.findScalarPos(u8, first, as_start, '(').?; + addr_space_name = try builder.string(first[name_start + "(".len .. first.len - ")".len]); + break first[as_start..name_start]; + }, + } else first[first.len..]; + const bit_width = std.fmt.parseInt(PointerSpec.BitWidth, field_it.next().?, 10) catch unreachable; + const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable); + const pref_align: Alignment = if (field_it.next()) |pref_align| + .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable) + else + abi_align; + const index_bit_width = if (field_it.next()) |index_bit_width| + std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable + else + bit_width; + assert(field_it.peek() == null); + + try pointer_specs.put(gpa, switch (addr_space.len) { + 0 => .default, + else => @fromBackingInt(std.fmt.parseInt(u24, addr_space, 10) catch unreachable), + }, .{ + .bit_width = bit_width, + .index_bit_width = index_bit_width, + .flags = .{ + .abi_align = abi_align, + .pref_align = pref_align, + .has_unstable_repr = has_unstable_repr, + .has_external_state = has_external_state, + .null_ptr_repr = null_ptr_repr orelse .all_zeros, + }, + .addr_space_name = addr_space_name, + }); + }, + 'i', 'f', 'v' => |kind| { + if (std.mem.eql(u8, spec, "ve")) { + vector_specs.clearRetainingCapacity(); + continue; + } + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + const bit_width = std.fmt.parseInt(PrimitiveSpec.BitWidth, field_it.first(), 10) catch unreachable; + const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable); + const pref_align: Alignment = if (field_it.next()) |pref_align| + .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable) + else + abi_align; + assert(field_it.peek() == null); + const specs = switch (kind) { + else => unreachable, + 'i' => &int_specs, + 'f' => &float_specs, + 'v' => &vector_specs, + }; + try specs.put(gpa, .{ .bit_width = bit_width, .abi_align = abi_align, .pref_align = pref_align }, {}); + }, + 'n' => { + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + if (std.mem.eql(u8, field_it.first(), "i")) { + while (field_it.next()) |non_integral_addr_space| try non_integral_addr_spaces.append( + gpa, + @fromBackingInt(std.fmt.parseInt(u24, non_integral_addr_space, 10) catch unreachable), + ); + } else { + field_it.reset(); + while (field_it.next()) |native_bit_width| { + _ = std.fmt.parseInt(PrimitiveSpec.BitWidth, native_bit_width, 10) catch unreachable; + } + } + }, + }; + + for (non_integral_addr_spaces.items) |non_integral_addr_space| { + const pointer_spec_gop = try pointer_specs.getOrPut(gpa, non_integral_addr_space); + if (!pointer_spec_gop.found_existing) pointer_spec_gop.value_ptr.* = pointer_specs.get(.default).?; + pointer_spec_gop.value_ptr.flags.has_unstable_repr = true; + pointer_spec_gop.value_ptr.flags.has_external_state = false; + } + + { + const SortContext = struct { + specs: []const PrimitiveSpec, + pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { + return ctx.specs[lhs_index].bit_width < ctx.specs[rhs_index].bit_width; + } + }; + int_specs.sortUnstable(SortContext{ .specs = int_specs.keys() }); + float_specs.sortUnstable(SortContext{ .specs = float_specs.keys() }); + vector_specs.sortUnstable(SortContext{ .specs = vector_specs.keys() }); + } + { + const SortContext = struct { + addr_spaces: []const AddrSpace, + pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { + return @backingInt(ctx.addr_spaces[lhs_index]) < @backingInt(ctx.addr_spaces[rhs_index]); + } + }; + pointer_specs.sortUnstable(SortContext{ .addr_spaces = pointer_specs.keys() }); + assert(pointer_specs.keys()[0] == .default); + } + + return .{ + .endian = endian, + .int_specs = int_specs.move(), + .float_specs = float_specs.move(), + .vector_specs = vector_specs.move(), + .pointer_specs = pointer_specs.move(), + .string_repr = string_repr, + }; + } + + pub fn deinit(data_layout: *DataLayout, gpa: Allocator) void { + data_layout.int_specs.deinit(gpa); + data_layout.float_specs.deinit(gpa); + data_layout.vector_specs.deinit(gpa); + data_layout.pointer_specs.deinit(gpa); + } + + pub fn getIntegerSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec { + const specs = data_layout.int_specs.keys(); + return specs[ + @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct { + fn order(ctx: PrimitiveSpec.BitWidth, spec: PrimitiveSpec) std.math.Order { + return std.math.order(ctx, spec.bit_width); + } + }.order), specs.len - 1) + ]; + } + + pub fn getFloatSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec { + if (data_layout.float_specs.getEntry(.{ + .bit_width = bit_width, + .abi_align = .default, + .pref_align = .default, + })) |entry| return entry.key_ptr.*; + const default_align: Alignment = .fromByteUnits( + std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, bit_width / 8), + ); + return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align }; + } + + pub fn getVectorSpec( + data_layout: *const DataLayout, + bit_width: PrimitiveSpec.BitWidth, + store_size: Type.Size, + ) PrimitiveSpec { + if (data_layout.float_specs.getEntry(.{ + .bit_width = bit_width, + .abi_align = .default, + .pref_align = .default, + })) |entry| return entry.key_ptr.*; + const default_align: Alignment = .fromByteUnits( + std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, switch (store_size) { + .fixed, .scalable => |known_min| known_min, + }), + ); + return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align }; + } + + pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec { + return data_layout.pointer_specs.get(addr_space) orelse data_layout.pointer_specs.values()[0]; + } +}; + pub const String = enum(u32) { none = maxInt(u31), empty, @@ -142,8 +591,8 @@ pub const String = enum(u32) { } fn fromIndex(index: ?usize) String { - return @fromBackingInt(@intCast(@as(u32, @intCast((index orelse return .none) + - @backingInt(String.empty))))); + return @fromBackingInt(@as(u32, @intCast((index orelse return .none) + + @backingInt(String.empty)))); } fn toIndex(self: String) ?usize { @@ -489,7 +938,10 @@ pub const Type = enum(u32) { .double, .i64, .x86_mmx => 64, .x86_fp80, .i80 => 80, .fp128, .ppc_fp128, .i128 => 128, - .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"), + .ptr => @intCast(builder.data_layout.getPointerSpec(.default).bit_width), + .@"ptr addrspace(4)" => @intCast( + builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(4))).bit_width, + ), _ => { const item = builder.type_items.items[@backingInt(self)]; return switch (item.tag) { @@ -498,7 +950,9 @@ pub const Type = enum(u32) { .vararg_function, => unreachable, .integer => @intCast(item.data), - .pointer => @panic("TODO: query data layout"), + .pointer => @intCast( + builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width, + ), .target => unreachable, .vector, .scalable_vector, @@ -931,12 +1385,74 @@ pub const Type = enum(u32) { }, }; } + + const Size = union(enum) { fixed: u64, scalable: u64 }; + pub fn bits(ty: Type, builder: *const Builder) Size { + const item = builder.type_items.items[@backingInt(ty)]; + return switch (item.tag) { + else => unreachable, + .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) { + else => unreachable, + .label => .{ .fixed = builder.data_layout.getPointerSpec(.default).bit_width }, + .half, .bfloat => .{ .fixed = 16 }, + .float => .{ .fixed = 32 }, + .double => .{ .fixed = 64 }, + .ppc_fp128, .fp128 => .{ .fixed = 128 }, + .x86_amx => .{ .fixed = 8192 }, + .x86_fp80 => .{ .fixed = 80 }, + }, + .integer => .{ .fixed = item.data }, + .pointer => .{ + .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width, + }, + }; + } + + pub fn alignment(ty: Type, kind: enum { abi, pref }, builder: *const Builder) Alignment { + const item = builder.type_items.items[@backingInt(ty)]; + switch (item.tag) { + else => unreachable, + .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) { + else => unreachable, + .label => { + const spec = builder.data_layout.getPointerSpec(.default); + return switch (kind) { + .abi => spec.flags.abi_align, + .pref => spec.flags.pref_align, + }; + }, + .half, .bfloat, .float, .double, .ppc_fp128, .fp128, .x86_fp80 => { + const spec = builder.data_layout.getFloatSpec(@intCast(ty.bits(builder).fixed)); + return switch (kind) { + .abi => spec.abi_align, + .pref => spec.pref_align, + }; + }, + .x86_amx => return comptime .fromByteUnits(64), + }, + .integer => { + const spec = builder.data_layout.getIntegerSpec(@intCast(item.data)); + return switch (kind) { + .abi => spec.abi_align, + .pref => spec.pref_align, + }; + }, + .pointer => { + const spec = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))); + return switch (kind) { + .abi => spec.flags.abi_align, + .pref => spec.flags.pref_align, + }; + }, + } + } }; pub const Attribute = union(Kind) { // Parameter Attributes zeroext, signext, + noext, inreg, byval: Type, byref: Type, @@ -947,6 +1463,7 @@ pub const Attribute = union(Kind) { @"align": Alignment.Lazy, @"noalias", nocapture, + captures: Captures, nofree, nest, returned, @@ -965,6 +1482,11 @@ pub const Attribute = union(Kind) { readnone, readonly, writeonly, + writable, + initializes: []const [2]u64, + dead_on_unwind, + dead_on_return: ?u32, + range: [2]Constant, // Function Attributes //alignstack: Alignment.Lazy, @@ -974,7 +1496,7 @@ pub const Attribute = union(Kind) { builtin, cold, convergent, - disable_sanitizer_information, + disable_sanitizer_instrumentation, fn_ret_thunk_extern, hot, inlinehint, @@ -984,6 +1506,7 @@ pub const Attribute = union(Kind) { naked, nobuiltin, nocallback, + nodivergencesource, noduplicate, //nofree, noimplicitfloat, @@ -1001,6 +1524,7 @@ pub const Attribute = union(Kind) { nosanitize_bounds, nosanitize_coverage, null_pointer_is_valid, + optdebug, optforfuzzing, optnone, optsize, @@ -1012,23 +1536,23 @@ pub const Attribute = union(Kind) { sanitize_thread, sanitize_hwaddress, sanitize_memtag, + sanitize_realtime, + sanitize_realtime_blocking, + sanitize_alloc_token, speculative_load_hardening, speculatable, ssp, sspstrong, sspreq, strictfp, + denormal_fpenv, uwtable: UwTable, nocf_check, shadowcallstack, mustprogress, vscale_range: VScaleRange, - - // Global Attributes - no_sanitize_address, - no_sanitize_hwaddress, - //sanitize_memtag, - sanitize_address_dyninit, + nooutline, + nocreateundeforpoison, string: struct { kind: String, value: String }, none: noreturn, @@ -1045,100 +1569,11 @@ pub const Attribute = union(Kind) { const storage = self.toStorage(builder); if (storage.kind.toString()) |kind| return .{ .string = .{ .kind = kind, - .value = @fromBackingInt(@intCast(storage.value)), + .value = @fromBackingInt(storage.value), } } else return switch (storage.kind) { - inline .zeroext, - .signext, - .inreg, - .byval, - .byref, - .preallocated, - .inalloca, - .sret, - .elementtype, - .@"align", - .@"noalias", - .nocapture, - .nofree, - .nest, - .returned, - .nonnull, - .dereferenceable, - .dereferenceable_or_null, - .swiftself, - .swiftasync, - .swifterror, - .immarg, - .noundef, - .nofpclass, - .alignstack, - .allocalign, - .allocptr, - .readnone, - .readonly, - .writeonly, - //.alignstack, - .allockind, - .allocsize, - .alwaysinline, - .builtin, - .cold, - .convergent, - .disable_sanitizer_information, - .fn_ret_thunk_extern, - .hot, - .inlinehint, - .jumptable, - .memory, - .minsize, - .naked, - .nobuiltin, - .nocallback, - .noduplicate, - //.nofree, - .noimplicitfloat, - .@"noinline", - .nomerge, - .nonlazybind, - .noprofile, - .skipprofile, - .noredzone, - .noreturn, - .norecurse, - .willreturn, - .nosync, - .nounwind, - .nosanitize_bounds, - .nosanitize_coverage, - .null_pointer_is_valid, - .optforfuzzing, - .optnone, - .optsize, - //.preallocated, - .returns_twice, - .safestack, - .sanitize_address, - .sanitize_memory, - .sanitize_thread, - .sanitize_hwaddress, - .sanitize_memtag, - .speculative_load_hardening, - .speculatable, - .ssp, - .sspstrong, - .sspreq, - .strictfp, - .uwtable, - .nocf_check, - .shadowcallstack, - .mustprogress, - .vscale_range, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, - => |kind| { + inline else => |kind| { const field_name, const field_type = comptime blk: { - @setEvalBranchQuota(10_000); + @setEvalBranchQuota(12_000); const info = @typeInfo(Attribute).@"union"; for (info.field_names, info.field_types) |field_name, field_type| { if (std.mem.eql(u8, field_name, @tagName(kind))) break :blk .{ field_name, field_type }; @@ -1149,14 +1584,17 @@ pub const Attribute = union(Kind) { return @unionInit(Attribute, field_name, switch (field_type) { void => {}, u32 => storage.value, - Alignment.Lazy, String, Type, UwTable => @fromBackingInt(@intCast(storage.value)), - AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value), + Alignment.Lazy, String, Type, UwTable => @fromBackingInt(storage.value), + AllocKind, AllocSize, Captures, FpClass, Memory, VScaleRange => @bitCast(storage.value), else => @compileError("bad payload type: " ++ field_name ++ ": " ++ @typeName(field_type)), }); }, - .string, .none => unreachable, - _ => unreachable, + .initializes, + .dead_on_return, + .range, + => @panic("TODO"), + .string, .none, _ => unreachable, }; } @@ -1174,6 +1612,7 @@ pub const Attribute = union(Kind) { switch (attribute) { .zeroext, .signext, + .noext, .inreg, .@"noalias", .nocapture, @@ -1191,11 +1630,13 @@ pub const Attribute = union(Kind) { .readnone, .readonly, .writeonly, + .writable, + .dead_on_unwind, .alwaysinline, .builtin, .cold, .convergent, - .disable_sanitizer_information, + .disable_sanitizer_instrumentation, .fn_ret_thunk_extern, .hot, .inlinehint, @@ -1204,6 +1645,7 @@ pub const Attribute = union(Kind) { .naked, .nobuiltin, .nocallback, + .nodivergencesource, .noduplicate, .noimplicitfloat, .@"noinline", @@ -1220,6 +1662,7 @@ pub const Attribute = union(Kind) { .nosanitize_bounds, .nosanitize_coverage, .null_pointer_is_valid, + .optdebug, .optforfuzzing, .optnone, .optsize, @@ -1230,18 +1673,21 @@ pub const Attribute = union(Kind) { .sanitize_thread, .sanitize_hwaddress, .sanitize_memtag, + .sanitize_realtime, + .sanitize_realtime_blocking, + .sanitize_alloc_token, .speculative_load_hardening, .speculatable, .ssp, .sspstrong, .sspreq, .strictfp, + .denormal_fpenv, .nocf_check, .shadowcallstack, .mustprogress, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, + .nooutline, + .nocreateundeforpoison, => try w.print(" {s}", .{@tagName(attribute)}), .byval, .byref, @@ -1254,6 +1700,45 @@ pub const Attribute = union(Kind) { .dereferenceable, .dereferenceable_or_null, => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }), + .captures => |captures| { + try w.print(" {s}(", .{@tagName(attribute)}); + var need_comma = false; + if (captures == Captures.none) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("none"); + need_comma = true; + } + inline for (@typeInfo(Captures).@"struct".field_names) |field_name| { + if (comptime std.mem.eql(u8, field_name, "_")) continue; + const components = @field(captures, field_name); + if (components != Captures.Components.none) { + if (!comptime std.mem.eql(u8, field_name, "other")) { + if (need_comma) try w.writeAll(", "); + try w.writeAll(field_name ++ ": "); + need_comma = false; + } + if (components.address) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("address"); + need_comma = true; + } else if (components.address_is_null) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("address_is_null"); + need_comma = true; + } + if (components.provenance) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("provenance"); + need_comma = true; + } else if (components.read_provenance) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("read_provenance"); + need_comma = true; + } + } + } + try w.writeByte(')'); + }, .nofpclass => |fpclass| { const Int = @typeInfo(FpClass).@"struct".backing_integer.?; try w.print(" {s}(", .{@tagName(attribute)}); @@ -1281,6 +1766,9 @@ pub const Attribute = union(Kind) { try w.print("({d})", .{alignment_bytes}); } }, + .initializes => @panic("TODO"), + .dead_on_return => @panic("TODO"), + .range => @panic("TODO"), .allockind => |allockind| { try w.print(" {t}(\"", .{attribute}); var any = false; @@ -1344,100 +1832,109 @@ pub const Attribute = union(Kind) { pub const Kind = enum(u32) { // Parameter Attributes - zeroext = 34, - signext = 24, - inreg = 5, - byval = 3, - byref = 69, - preallocated = 65, - inalloca = 38, - sret = 29, // TODO: ? - elementtype = 77, - @"align" = 1, - @"noalias" = 9, - nocapture = 11, - nofree = 62, - nest = 8, - returned = 22, - nonnull = 39, - dereferenceable = 41, - dereferenceable_or_null = 42, - swiftself = 46, - swiftasync = 75, - swifterror = 47, - immarg = 60, - noundef = 68, - nofpclass = 87, - alignstack = 25, - allocalign = 80, - allocptr = 81, - readnone = 20, - readonly = 21, - writeonly = 52, + zeroext = @backingInt(ATTR_KIND.Z_EXT), + signext = @backingInt(ATTR_KIND.S_EXT), + noext = @backingInt(ATTR_KIND.NO_EXT), + inreg = @backingInt(ATTR_KIND.IN_REG), + byval = @backingInt(ATTR_KIND.BY_VAL), + byref = @backingInt(ATTR_KIND.BYREF), + preallocated = @backingInt(ATTR_KIND.PREALLOCATED), + inalloca = @backingInt(ATTR_KIND.IN_ALLOCA), + sret = @backingInt(ATTR_KIND.STRUCT_RET), + elementtype = @backingInt(ATTR_KIND.ELEMENTTYPE), + @"align" = @backingInt(ATTR_KIND.ALIGNMENT), + @"noalias" = @backingInt(ATTR_KIND.NO_ALIAS), + nocapture = @backingInt(ATTR_KIND.NO_CAPTURE), + captures = @backingInt(ATTR_KIND.CAPTURES), + nofree = @backingInt(ATTR_KIND.NOFREE), + nest = @backingInt(ATTR_KIND.NEST), + returned = @backingInt(ATTR_KIND.RETURNED), + nonnull = @backingInt(ATTR_KIND.NON_NULL), + dereferenceable = @backingInt(ATTR_KIND.DEREFERENCEABLE), + dereferenceable_or_null = @backingInt(ATTR_KIND.DEREFERENCEABLE_OR_NULL), + swiftself = @backingInt(ATTR_KIND.SWIFT_SELF), + swiftasync = @backingInt(ATTR_KIND.SWIFT_ASYNC), + swifterror = @backingInt(ATTR_KIND.SWIFT_ERROR), + immarg = @backingInt(ATTR_KIND.IMMARG), + noundef = @backingInt(ATTR_KIND.NOUNDEF), + nofpclass = @backingInt(ATTR_KIND.NOFPCLASS), + alignstack = @backingInt(ATTR_KIND.STACK_ALIGNMENT), + allocalign = @backingInt(ATTR_KIND.ALLOC_ALIGN), + allocptr = @backingInt(ATTR_KIND.ALLOCATED_POINTER), + readnone = @backingInt(ATTR_KIND.READ_NONE), + readonly = @backingInt(ATTR_KIND.READ_ONLY), + writeonly = @backingInt(ATTR_KIND.WRITEONLY), + writable = @backingInt(ATTR_KIND.WRITABLE), + initializes = @backingInt(ATTR_KIND.INITIALIZES), + dead_on_unwind = @backingInt(ATTR_KIND.DEAD_ON_UNWIND), + dead_on_return = @backingInt(ATTR_KIND.DEAD_ON_RETURN), + range = @backingInt(ATTR_KIND.RANGE), // Function Attributes - //alignstack, - allockind = 82, - allocsize = 51, - alwaysinline = 2, - builtin = 35, - cold = 36, - convergent = 43, - disable_sanitizer_information = 78, - fn_ret_thunk_extern = 84, - hot = 72, - inlinehint = 4, - jumptable = 40, - memory = 86, - minsize = 6, - naked = 7, - nobuiltin = 10, - nocallback = 71, - noduplicate = 12, - //nofree, - noimplicitfloat = 13, - @"noinline" = 14, - nomerge = 66, - nonlazybind = 15, - noprofile = 73, - skipprofile = 85, - noredzone = 16, - noreturn = 17, - norecurse = 48, - willreturn = 61, - nosync = 63, - nounwind = 18, - nosanitize_bounds = 79, - nosanitize_coverage = 76, - null_pointer_is_valid = 67, - optforfuzzing = 57, - optnone = 37, - optsize = 19, - //preallocated, - returns_twice = 23, - safestack = 44, - sanitize_address = 30, - sanitize_memory = 32, - sanitize_thread = 31, - sanitize_hwaddress = 55, - sanitize_memtag = 64, - speculative_load_hardening = 59, - speculatable = 53, - ssp = 26, - sspstrong = 28, - sspreq = 27, - strictfp = 54, - uwtable = 33, - nocf_check = 56, - shadowcallstack = 58, - mustprogress = 70, - vscale_range = 74, - - // Global Attributes - no_sanitize_address = 100, - no_sanitize_hwaddress = 101, - //sanitize_memtag, - sanitize_address_dyninit = 102, + //alignstack = @intFromEnum(ATTR_KIND.STACK_ALIGNMENT), + allockind = @backingInt(ATTR_KIND.ALLOC_KIND), + allocsize = @backingInt(ATTR_KIND.ALLOC_SIZE), + alwaysinline = @backingInt(ATTR_KIND.ALWAYS_INLINE), + builtin = @backingInt(ATTR_KIND.BUILTIN), + cold = @backingInt(ATTR_KIND.COLD), + convergent = @backingInt(ATTR_KIND.CONVERGENT), + disable_sanitizer_instrumentation = @backingInt(ATTR_KIND.DISABLE_SANITIZER_INSTRUMENTATION), + fn_ret_thunk_extern = @backingInt(ATTR_KIND.FNRETTHUNK_EXTERN), + hot = @backingInt(ATTR_KIND.HOT), + inlinehint = @backingInt(ATTR_KIND.INLINE_HINT), + jumptable = @backingInt(ATTR_KIND.JUMP_TABLE), + memory = @backingInt(ATTR_KIND.MEMORY), + minsize = @backingInt(ATTR_KIND.MIN_SIZE), + naked = @backingInt(ATTR_KIND.NAKED), + nobuiltin = @backingInt(ATTR_KIND.NO_BUILTIN), + nocallback = @backingInt(ATTR_KIND.NO_CALLBACK), + nodivergencesource = @backingInt(ATTR_KIND.NO_DIVERGENCE_SOURCE), + noduplicate = @backingInt(ATTR_KIND.NO_DUPLICATE), + //nofree = @intFromEnum(ATTR_KIND.NOFREE), + noimplicitfloat = @backingInt(ATTR_KIND.NO_IMPLICIT_FLOAT), + @"noinline" = @backingInt(ATTR_KIND.NO_INLINE), + nomerge = @backingInt(ATTR_KIND.NO_MERGE), + nonlazybind = @backingInt(ATTR_KIND.NON_LAZY_BIND), + noprofile = @backingInt(ATTR_KIND.NO_PROFILE), + skipprofile = @backingInt(ATTR_KIND.SKIP_PROFILE), + noredzone = @backingInt(ATTR_KIND.NO_RED_ZONE), + noreturn = @backingInt(ATTR_KIND.NO_RETURN), + norecurse = @backingInt(ATTR_KIND.NO_RECURSE), + willreturn = @backingInt(ATTR_KIND.WILLRETURN), + nosync = @backingInt(ATTR_KIND.NOSYNC), + nounwind = @backingInt(ATTR_KIND.NO_UNWIND), + nosanitize_bounds = @backingInt(ATTR_KIND.NO_SANITIZE_BOUNDS), + nosanitize_coverage = @backingInt(ATTR_KIND.NO_SANITIZE_COVERAGE), + null_pointer_is_valid = @backingInt(ATTR_KIND.NULL_POINTER_IS_VALID), + optdebug = @backingInt(ATTR_KIND.OPTIMIZE_FOR_DEBUGGING), + optforfuzzing = @backingInt(ATTR_KIND.OPT_FOR_FUZZING), + optnone = @backingInt(ATTR_KIND.OPTIMIZE_NONE), + optsize = @backingInt(ATTR_KIND.OPTIMIZE_FOR_SIZE), + //preallocated = @intFromEnum(ATTR_KIND.PREALLOCATED), + returns_twice = @backingInt(ATTR_KIND.RETURNS_TWICE), + safestack = @backingInt(ATTR_KIND.SAFESTACK), + sanitize_address = @backingInt(ATTR_KIND.SANITIZE_ADDRESS), + sanitize_memory = @backingInt(ATTR_KIND.SANITIZE_MEMORY), + sanitize_thread = @backingInt(ATTR_KIND.SANITIZE_THREAD), + sanitize_hwaddress = @backingInt(ATTR_KIND.SANITIZE_HWADDRESS), + sanitize_memtag = @backingInt(ATTR_KIND.SANITIZE_MEMTAG), + sanitize_realtime = @backingInt(ATTR_KIND.SANITIZE_REALTIME), + sanitize_realtime_blocking = @backingInt(ATTR_KIND.SANITIZE_REALTIME_BLOCKING), + sanitize_alloc_token = @backingInt(ATTR_KIND.SANITIZE_ALLOC_TOKEN), + speculative_load_hardening = @backingInt(ATTR_KIND.SPECULATIVE_LOAD_HARDENING), + speculatable = @backingInt(ATTR_KIND.SPECULATABLE), + ssp = @backingInt(ATTR_KIND.STACK_PROTECT), + sspstrong = @backingInt(ATTR_KIND.STACK_PROTECT_STRONG), + sspreq = @backingInt(ATTR_KIND.STACK_PROTECT_REQ), + strictfp = @backingInt(ATTR_KIND.STRICT_FP), + denormal_fpenv = @backingInt(ATTR_KIND.DENORMAL_FPENV), + uwtable = @backingInt(ATTR_KIND.UW_TABLE), + nocf_check = @backingInt(ATTR_KIND.NOCF_CHECK), + shadowcallstack = @backingInt(ATTR_KIND.SHADOWCALLSTACK), + mustprogress = @backingInt(ATTR_KIND.MUSTPROGRESS), + vscale_range = @backingInt(ATTR_KIND.VSCALE_RANGE), + nooutline = @backingInt(ATTR_KIND.NOOUTLINE), + nocreateundeforpoison = @backingInt(ATTR_KIND.NO_CREATE_UNDEF_OR_POISON), string = maxInt(u31), none = maxInt(u32), @@ -1447,16 +1944,128 @@ pub const Attribute = union(Kind) { pub fn fromString(str: String) Kind { assert(!str.isAnon()); - const kind: Kind = @fromBackingInt(@intCast(@backingInt(str))); + const kind: Kind = @fromBackingInt(@backingInt(str)); assert(kind != .none); return kind; } fn toString(self: Kind) ?String { assert(self != .none); - const str: String = @fromBackingInt(@intCast(@backingInt(self))); + const str: String = @fromBackingInt(@backingInt(self)); return if (str.isAnon()) null else str; } + + /// enum AttributeKindCodes + const ATTR_KIND = enum(u32) { + ALIGNMENT = 1, + ALWAYS_INLINE = 2, + BY_VAL = 3, + INLINE_HINT = 4, + IN_REG = 5, + MIN_SIZE = 6, + NAKED = 7, + NEST = 8, + NO_ALIAS = 9, + NO_BUILTIN = 10, + NO_CAPTURE = 11, + NO_DUPLICATE = 12, + NO_IMPLICIT_FLOAT = 13, + NO_INLINE = 14, + NON_LAZY_BIND = 15, + NO_RED_ZONE = 16, + NO_RETURN = 17, + NO_UNWIND = 18, + OPTIMIZE_FOR_SIZE = 19, + READ_NONE = 20, + READ_ONLY = 21, + RETURNED = 22, + RETURNS_TWICE = 23, + S_EXT = 24, + STACK_ALIGNMENT = 25, + STACK_PROTECT = 26, + STACK_PROTECT_REQ = 27, + STACK_PROTECT_STRONG = 28, + STRUCT_RET = 29, + SANITIZE_ADDRESS = 30, + SANITIZE_THREAD = 31, + SANITIZE_MEMORY = 32, + UW_TABLE = 33, + Z_EXT = 34, + BUILTIN = 35, + COLD = 36, + OPTIMIZE_NONE = 37, + IN_ALLOCA = 38, + NON_NULL = 39, + JUMP_TABLE = 40, + DEREFERENCEABLE = 41, + DEREFERENCEABLE_OR_NULL = 42, + CONVERGENT = 43, + SAFESTACK = 44, + ARGMEMONLY = 45, + SWIFT_SELF = 46, + SWIFT_ERROR = 47, + NO_RECURSE = 48, + INACCESSIBLEMEM_ONLY = 49, + INACCESSIBLEMEM_OR_ARGMEMONLY = 50, + ALLOC_SIZE = 51, + WRITEONLY = 52, + SPECULATABLE = 53, + STRICT_FP = 54, + SANITIZE_HWADDRESS = 55, + NOCF_CHECK = 56, + OPT_FOR_FUZZING = 57, + SHADOWCALLSTACK = 58, + SPECULATIVE_LOAD_HARDENING = 59, + IMMARG = 60, + WILLRETURN = 61, + NOFREE = 62, + NOSYNC = 63, + SANITIZE_MEMTAG = 64, + PREALLOCATED = 65, + NO_MERGE = 66, + NULL_POINTER_IS_VALID = 67, + NOUNDEF = 68, + BYREF = 69, + MUSTPROGRESS = 70, + NO_CALLBACK = 71, + HOT = 72, + NO_PROFILE = 73, + VSCALE_RANGE = 74, + SWIFT_ASYNC = 75, + NO_SANITIZE_COVERAGE = 76, + ELEMENTTYPE = 77, + DISABLE_SANITIZER_INSTRUMENTATION = 78, + NO_SANITIZE_BOUNDS = 79, + ALLOC_ALIGN = 80, + ALLOCATED_POINTER = 81, + ALLOC_KIND = 82, + PRESPLIT_COROUTINE = 83, + FNRETTHUNK_EXTERN = 84, + SKIP_PROFILE = 85, + MEMORY = 86, + NOFPCLASS = 87, + OPTIMIZE_FOR_DEBUGGING = 88, + WRITABLE = 89, + CORO_ONLY_DESTROY_WHEN_COMPLETE = 90, + DEAD_ON_UNWIND = 91, + RANGE = 92, + SANITIZE_NUMERICAL_STABILITY = 93, + INITIALIZES = 94, + HYBRID_PATCHABLE = 95, + SANITIZE_REALTIME = 96, + SANITIZE_REALTIME_BLOCKING = 97, + CORO_ELIDE_SAFE = 98, + NO_EXT = 99, + NO_DIVERGENCE_SOURCE = 100, + SANITIZE_TYPE = 101, + CAPTURES = 102, + DEAD_ON_RETURN = 103, + SANITIZE_ALLOC_TOKEN = 104, + NO_CREATE_UNDEF_OR_POISON = 105, + DENORMAL_FPENV = 106, + NOOUTLINE = 107, + FLATTEN = 108, + }; }; pub const FpClass = packed struct(u32) { @@ -1506,6 +2115,29 @@ pub const Attribute = union(Kind) { pub const pnorm = FpClass{ .positive_normal = true }; }; + pub const Captures = packed struct(u32) { + other: Components = .none, + ret: Components = .none, + _: u24 = 0, + + pub const none: Captures = .{}; + + pub const Components = packed struct(u4) { + address_is_null: bool = false, + address: bool = false, + read_provenance: bool = false, + provenance: bool = false, + + pub const none: Components = .{}; + pub const all: Components = .{ + .address_is_null = true, + .address = true, + .read_provenance = true, + .provenance = true, + }; + }; + }; + pub const AllocKind = packed struct(u32) { alloc: bool, realloc: bool, @@ -1582,9 +2214,13 @@ pub const Attribute = union(Kind) { void => 0, u32 => value, Alignment.Lazy, String, Type, UwTable => @backingInt(value), - AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value), - else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))), + AllocKind, AllocSize, Captures, FpClass, Memory, VScaleRange => @bitCast(value), + else => @compileError("bad payload type: " ++ @tagName(tag) ++ ": " ++ @typeName(@TypeOf(value))), } }, + .initializes, + .dead_on_return, + .range, + => @panic("TODO"), .string => |string_attr| .{ .kind = Kind.fromString(string_attr.kind), .value = @backingInt(string_attr.value), @@ -1907,87 +2543,87 @@ pub const AddrSpace = enum(u24) { // See llvm/lib/Target/X86/X86.h pub const x86 = struct { - pub const gs: AddrSpace = @fromBackingInt(@intCast(256)); - pub const fs: AddrSpace = @fromBackingInt(@intCast(257)); - pub const ss: AddrSpace = @fromBackingInt(@intCast(258)); + pub const gs: AddrSpace = @fromBackingInt(256); + pub const fs: AddrSpace = @fromBackingInt(257); + pub const ss: AddrSpace = @fromBackingInt(258); - pub const ptr32_sptr: AddrSpace = @fromBackingInt(@intCast(270)); - pub const ptr32_uptr: AddrSpace = @fromBackingInt(@intCast(271)); - pub const ptr64: AddrSpace = @fromBackingInt(@intCast(272)); + pub const ptr32_sptr: AddrSpace = @fromBackingInt(270); + pub const ptr32_uptr: AddrSpace = @fromBackingInt(271); + pub const ptr64: AddrSpace = @fromBackingInt(272); }; pub const x86_64 = x86; // See llvm/lib/Target/AVR/AVR.h pub const avr = struct { - pub const data: AddrSpace = @fromBackingInt(@intCast(0)); - pub const program: AddrSpace = @fromBackingInt(@intCast(1)); - pub const program1: AddrSpace = @fromBackingInt(@intCast(2)); - pub const program2: AddrSpace = @fromBackingInt(@intCast(3)); - pub const program3: AddrSpace = @fromBackingInt(@intCast(4)); - pub const program4: AddrSpace = @fromBackingInt(@intCast(5)); - pub const program5: AddrSpace = @fromBackingInt(@intCast(6)); + pub const data: AddrSpace = @fromBackingInt(0); + pub const program: AddrSpace = @fromBackingInt(1); + pub const program1: AddrSpace = @fromBackingInt(2); + pub const program2: AddrSpace = @fromBackingInt(3); + pub const program3: AddrSpace = @fromBackingInt(4); + pub const program4: AddrSpace = @fromBackingInt(5); + pub const program5: AddrSpace = @fromBackingInt(6); }; // See llvm/lib/Target/NVPTX/NVPTX.h pub const nvptx = struct { - pub const generic: AddrSpace = @fromBackingInt(@intCast(0)); - pub const global: AddrSpace = @fromBackingInt(@intCast(1)); - pub const constant: AddrSpace = @fromBackingInt(@intCast(2)); - pub const shared: AddrSpace = @fromBackingInt(@intCast(3)); - pub const param: AddrSpace = @fromBackingInt(@intCast(4)); - pub const local: AddrSpace = @fromBackingInt(@intCast(5)); + pub const generic: AddrSpace = @fromBackingInt(0); + pub const global: AddrSpace = @fromBackingInt(1); + pub const constant: AddrSpace = @fromBackingInt(2); + pub const shared: AddrSpace = @fromBackingInt(3); + pub const param: AddrSpace = @fromBackingInt(4); + pub const local: AddrSpace = @fromBackingInt(5); }; // See llvm/lib/Target/AMDGPU/AMDGPU.h pub const amdgpu = struct { - pub const flat: AddrSpace = @fromBackingInt(@intCast(0)); - pub const global: AddrSpace = @fromBackingInt(@intCast(1)); - pub const region: AddrSpace = @fromBackingInt(@intCast(2)); - pub const local: AddrSpace = @fromBackingInt(@intCast(3)); - pub const constant: AddrSpace = @fromBackingInt(@intCast(4)); - pub const private: AddrSpace = @fromBackingInt(@intCast(5)); - pub const constant_32bit: AddrSpace = @fromBackingInt(@intCast(6)); - pub const buffer_fat_pointer: AddrSpace = @fromBackingInt(@intCast(7)); - pub const buffer_resource: AddrSpace = @fromBackingInt(@intCast(8)); - pub const buffer_strided_pointer: AddrSpace = @fromBackingInt(@intCast(9)); - pub const param_d: AddrSpace = @fromBackingInt(@intCast(6)); - pub const param_i: AddrSpace = @fromBackingInt(@intCast(7)); - pub const constant_buffer_0: AddrSpace = @fromBackingInt(@intCast(8)); - pub const constant_buffer_1: AddrSpace = @fromBackingInt(@intCast(9)); - pub const constant_buffer_2: AddrSpace = @fromBackingInt(@intCast(10)); - pub const constant_buffer_3: AddrSpace = @fromBackingInt(@intCast(11)); - pub const constant_buffer_4: AddrSpace = @fromBackingInt(@intCast(12)); - pub const constant_buffer_5: AddrSpace = @fromBackingInt(@intCast(13)); - pub const constant_buffer_6: AddrSpace = @fromBackingInt(@intCast(14)); - pub const constant_buffer_7: AddrSpace = @fromBackingInt(@intCast(15)); - pub const constant_buffer_8: AddrSpace = @fromBackingInt(@intCast(16)); - pub const constant_buffer_9: AddrSpace = @fromBackingInt(@intCast(17)); - pub const constant_buffer_10: AddrSpace = @fromBackingInt(@intCast(18)); - pub const constant_buffer_11: AddrSpace = @fromBackingInt(@intCast(19)); - pub const constant_buffer_12: AddrSpace = @fromBackingInt(@intCast(20)); - pub const constant_buffer_13: AddrSpace = @fromBackingInt(@intCast(21)); - pub const constant_buffer_14: AddrSpace = @fromBackingInt(@intCast(22)); - pub const constant_buffer_15: AddrSpace = @fromBackingInt(@intCast(23)); - pub const streamout_register: AddrSpace = @fromBackingInt(@intCast(128)); + pub const flat: AddrSpace = @fromBackingInt(0); + pub const global: AddrSpace = @fromBackingInt(1); + pub const region: AddrSpace = @fromBackingInt(2); + pub const local: AddrSpace = @fromBackingInt(3); + pub const constant: AddrSpace = @fromBackingInt(4); + pub const private: AddrSpace = @fromBackingInt(5); + pub const constant_32bit: AddrSpace = @fromBackingInt(6); + pub const buffer_fat_pointer: AddrSpace = @fromBackingInt(7); + pub const buffer_resource: AddrSpace = @fromBackingInt(8); + pub const buffer_strided_pointer: AddrSpace = @fromBackingInt(9); + pub const param_d: AddrSpace = @fromBackingInt(6); + pub const param_i: AddrSpace = @fromBackingInt(7); + pub const constant_buffer_0: AddrSpace = @fromBackingInt(8); + pub const constant_buffer_1: AddrSpace = @fromBackingInt(9); + pub const constant_buffer_2: AddrSpace = @fromBackingInt(10); + pub const constant_buffer_3: AddrSpace = @fromBackingInt(11); + pub const constant_buffer_4: AddrSpace = @fromBackingInt(12); + pub const constant_buffer_5: AddrSpace = @fromBackingInt(13); + pub const constant_buffer_6: AddrSpace = @fromBackingInt(14); + pub const constant_buffer_7: AddrSpace = @fromBackingInt(15); + pub const constant_buffer_8: AddrSpace = @fromBackingInt(16); + pub const constant_buffer_9: AddrSpace = @fromBackingInt(17); + pub const constant_buffer_10: AddrSpace = @fromBackingInt(18); + pub const constant_buffer_11: AddrSpace = @fromBackingInt(19); + pub const constant_buffer_12: AddrSpace = @fromBackingInt(20); + pub const constant_buffer_13: AddrSpace = @fromBackingInt(21); + pub const constant_buffer_14: AddrSpace = @fromBackingInt(22); + pub const constant_buffer_15: AddrSpace = @fromBackingInt(23); + pub const streamout_register: AddrSpace = @fromBackingInt(128); }; pub const spirv = struct { - pub const function: AddrSpace = @fromBackingInt(@intCast(0)); - pub const cross_workgroup: AddrSpace = @fromBackingInt(@intCast(1)); - pub const uniform_constant: AddrSpace = @fromBackingInt(@intCast(2)); - pub const workgroup: AddrSpace = @fromBackingInt(@intCast(3)); - pub const generic: AddrSpace = @fromBackingInt(@intCast(4)); - pub const device_only_intel: AddrSpace = @fromBackingInt(@intCast(5)); - pub const host_only_intel: AddrSpace = @fromBackingInt(@intCast(6)); - pub const input: AddrSpace = @fromBackingInt(@intCast(7)); + pub const function: AddrSpace = @fromBackingInt(0); + pub const cross_workgroup: AddrSpace = @fromBackingInt(1); + pub const uniform_constant: AddrSpace = @fromBackingInt(2); + pub const workgroup: AddrSpace = @fromBackingInt(3); + pub const generic: AddrSpace = @fromBackingInt(4); + pub const device_only_intel: AddrSpace = @fromBackingInt(5); + pub const host_only_intel: AddrSpace = @fromBackingInt(6); + pub const input: AddrSpace = @fromBackingInt(7); }; // See llvm/include/llvm/CodeGen/WasmAddressSpaces.h pub const wasm = struct { - pub const default: AddrSpace = @fromBackingInt(@intCast(0)); - pub const variable: AddrSpace = @fromBackingInt(@intCast(1)); - pub const externref: AddrSpace = @fromBackingInt(@intCast(10)); - pub const funcref: AddrSpace = @fromBackingInt(@intCast(20)); + pub const default: AddrSpace = @fromBackingInt(0); + pub const variable: AddrSpace = @fromBackingInt(1); + pub const externref: AddrSpace = @fromBackingInt(10); + pub const funcref: AddrSpace = @fromBackingInt(20); }; pub fn format(addr_space: AddrSpace, w: *Writer) Writer.Error!void { @@ -2030,7 +2666,7 @@ pub const Alignment = enum(u6) { _, pub fn wrap(a: Alignment) Lazy { - return @fromBackingInt(@intCast(@backingInt(a))); + return @fromBackingInt(@backingInt(a)); } pub fn resolve(l: Lazy, b: *const Builder) Alignment { return switch (@backingInt(l)) { @@ -2061,11 +2697,18 @@ pub const Alignment = enum(u6) { }; } - /// Asserts that neither `a` nor `b` is `.default`. - pub fn max(a: Alignment, b: Alignment) Alignment { - assert(a != .default); - assert(b != .default); - return @fromBackingInt(@intCast(@max(@backingInt(a), @backingInt(b)))); + /// Asserts that neither `lhs` nor `rhs` is `.default`. + pub fn max(lhs: Alignment, rhs: Alignment) Alignment { + assert(lhs != .default); + assert(rhs != .default); + return @fromBackingInt(@max(@backingInt(lhs), @backingInt(rhs))); + } + + /// Asserts that neither `lhs` nor `rhs` is `.default`. + pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order { + assert(lhs != .default); + assert(rhs != .default); + return std.math.order(@backingInt(lhs), @backingInt(rhs)); } pub fn toLlvm(self: Alignment) u6 { @@ -2261,8 +2904,7 @@ pub const StrtabString = enum(u32) { } fn fromIndex(index: ?usize) StrtabString { - return @fromBackingInt(@intCast(@as(u32, @intCast((index orelse return .none) + - @backingInt(StrtabString.empty))))); + return @fromBackingInt(@intCast((index orelse return .none) + @backingInt(StrtabString.empty))); } fn toIndex(self: StrtabString) ?usize { @@ -2398,7 +3040,7 @@ pub const Global = struct { } pub fn toConst(global: Index) Constant { - return @fromBackingInt(@intCast(@backingInt(Constant.first_global) + @backingInt(global))); + return @fromBackingInt(@backingInt(Constant.first_global) + @backingInt(global)); } pub fn toValue(global: Index) Value { @@ -2526,7 +3168,7 @@ pub const Global = struct { _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]); builder.globals.swapRemoveAt(index); if (!old_name.isAnon()) return; - builder.next_unnamed_global = @fromBackingInt(@intCast(@backingInt(builder.next_unnamed_global) - 1)); + builder.next_unnamed_global = @fromBackingInt(@backingInt(builder.next_unnamed_global) - 1); if (builder.next_unnamed_global == old_name) return; builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder); } @@ -2539,7 +3181,7 @@ pub const Global = struct { fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void { if (self.eql(other, builder)) return; - builder.next_replaced_global = @fromBackingInt(@intCast(@backingInt(builder.next_replaced_global) - 1)); + builder.next_replaced_global = @fromBackingInt(@backingInt(builder.next_replaced_global) - 1); self.renameAssumeCapacity(builder.next_replaced_global, builder); self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) }; } @@ -2699,6 +3341,8 @@ pub const Intrinsic = enum { smin, umax, umin, + scmp, + ucmp, memcpy, @"memcpy.inline", memmove, @@ -2708,10 +3352,21 @@ pub const Intrinsic = enum { powi, sin, cos, + tan, + asin, + acos, + atan, + atan2, + sinh, + cosh, + tanh, + sincos, + sincospi, + modf, pow, exp, - exp10, exp2, + exp10, ldexp, frexp, log, @@ -2723,6 +3378,8 @@ pub const Intrinsic = enum { maxnum, minimum, maximum, + minimumnum, + maximumnum, copysign, floor, ceil, @@ -2744,6 +3401,7 @@ pub const Intrinsic = enum { cttz, fshl, fshr, + clmul, // Arithmetic with Overflow @"sadd.with.overflow", @@ -2904,21 +3562,21 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .ptr } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .addressofreturnaddress = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .sponentry = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .frameaddress = .{ .ret_len = 1, @@ -2926,7 +3584,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .prefetch = .{ .ret_len = 0, @@ -2936,14 +3594,14 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.readwrite) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.readwrite) } }, }, .@"thread.pointer" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .ptr } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .abs = .{ @@ -2953,7 +3611,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .smax = .{ .ret_len = 1, @@ -2962,7 +3620,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .smin = .{ .ret_len = 1, @@ -2971,7 +3629,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .umax = .{ .ret_len = 1, @@ -2980,7 +3638,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .umin = .{ .ret_len = 1, @@ -2989,7 +3647,25 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .scmp = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 1 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .ucmp = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 1 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .memcpy = .{ .ret_len = 0, @@ -3047,7 +3723,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .powi = .{ .ret_len = 1, @@ -3056,7 +3732,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .sin = .{ .ret_len = 1, @@ -3064,7 +3740,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .cos = .{ .ret_len = 1, @@ -3072,7 +3748,99 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .tan = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .asin = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .acos = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .atan = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .atan2 = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sinh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .cosh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .tanh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sincos = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sincospi = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .modf = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .pow = .{ .ret_len = 1, @@ -3081,7 +3849,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp = .{ .ret_len = 1, @@ -3089,7 +3857,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp2 = .{ .ret_len = 1, @@ -3097,7 +3865,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp10 = .{ .ret_len = 1, @@ -3105,7 +3873,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ldexp = .{ .ret_len = 1, @@ -3114,7 +3882,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .frexp = .{ .ret_len = 2, @@ -3123,7 +3891,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log = .{ .ret_len = 1, @@ -3131,7 +3899,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log10 = .{ .ret_len = 1, @@ -3139,7 +3907,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log2 = .{ .ret_len = 1, @@ -3147,7 +3915,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fma = .{ .ret_len = 1, @@ -3157,7 +3925,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fabs = .{ .ret_len = 1, @@ -3165,7 +3933,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .minnum = .{ .ret_len = 1, @@ -3174,7 +3942,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .maxnum = .{ .ret_len = 1, @@ -3183,7 +3951,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .minimum = .{ .ret_len = 1, @@ -3192,7 +3960,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .maximum = .{ .ret_len = 1, @@ -3201,7 +3969,25 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .minimumnum = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .maximumnum = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .copysign = .{ .ret_len = 1, @@ -3210,7 +3996,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .floor = .{ .ret_len = 1, @@ -3218,7 +4004,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ceil = .{ .ret_len = 1, @@ -3226,7 +4012,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .trunc = .{ .ret_len = 1, @@ -3234,7 +4020,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .rint = .{ .ret_len = 1, @@ -3242,7 +4028,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .nearbyint = .{ .ret_len = 1, @@ -3250,7 +4036,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .round = .{ .ret_len = 1, @@ -3258,7 +4044,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .roundeven = .{ .ret_len = 1, @@ -3266,7 +4052,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .lround = .{ .ret_len = 1, @@ -3274,7 +4060,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .llround = .{ .ret_len = 1, @@ -3282,7 +4068,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .lrint = .{ .ret_len = 1, @@ -3290,7 +4076,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .llrint = .{ .ret_len = 1, @@ -3298,7 +4084,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .bitreverse = .{ @@ -3307,7 +4093,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .bswap = .{ .ret_len = 1, @@ -3315,7 +4101,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ctpop = .{ .ret_len = 1, @@ -3323,7 +4109,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ctlz = .{ .ret_len = 1, @@ -3332,7 +4118,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .cttz = .{ .ret_len = 1, @@ -3341,7 +4127,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fshl = .{ .ret_len = 1, @@ -3351,7 +4137,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fshr = .{ .ret_len = 1, @@ -3361,7 +4147,16 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .clmul = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sadd.with.overflow" = .{ @@ -3372,7 +4167,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"uadd.with.overflow" = .{ .ret_len = 2, @@ -3382,7 +4177,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ssub.with.overflow" = .{ .ret_len = 2, @@ -3392,7 +4187,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"usub.with.overflow" = .{ .ret_len = 2, @@ -3402,7 +4197,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.with.overflow" = .{ .ret_len = 2, @@ -3412,7 +4207,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.with.overflow" = .{ .ret_len = 2, @@ -3422,7 +4217,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sadd.sat" = .{ @@ -3432,7 +4227,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"uadd.sat" = .{ .ret_len = 1, @@ -3441,7 +4236,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ssub.sat" = .{ .ret_len = 1, @@ -3450,7 +4245,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"usub.sat" = .{ .ret_len = 1, @@ -3459,7 +4254,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sshl.sat" = .{ .ret_len = 1, @@ -3468,7 +4263,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ushl.sat" = .{ .ret_len = 1, @@ -3477,7 +4272,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.fix" = .{ @@ -3488,7 +4283,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.fix" = .{ .ret_len = 1, @@ -3498,7 +4293,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.fix.sat" = .{ .ret_len = 1, @@ -3508,7 +4303,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.fix.sat" = .{ .ret_len = 1, @@ -3518,7 +4313,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sdiv.fix" = .{ .ret_len = 1, @@ -3528,7 +4323,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"udiv.fix" = .{ .ret_len = 1, @@ -3538,7 +4333,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"sdiv.fix.sat" = .{ .ret_len = 1, @@ -3548,7 +4343,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"udiv.fix.sat" = .{ .ret_len = 1, @@ -3558,7 +4353,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .canonicalize = .{ @@ -3567,7 +4362,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fmuladd = .{ .ret_len = 1, @@ -3577,7 +4372,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.add" = .{ @@ -3586,7 +4381,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fadd" = .{ .ret_len = 1, @@ -3595,7 +4390,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 2 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.mul" = .{ .ret_len = 1, @@ -3603,7 +4398,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmul" = .{ .ret_len = 1, @@ -3612,7 +4407,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 2 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.and" = .{ .ret_len = 1, @@ -3620,7 +4415,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.or" = .{ .ret_len = 1, @@ -3628,7 +4423,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.xor" = .{ .ret_len = 1, @@ -3636,7 +4431,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.smax" = .{ .ret_len = 1, @@ -3644,7 +4439,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.smin" = .{ .ret_len = 1, @@ -3652,7 +4447,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.umax" = .{ .ret_len = 1, @@ -3660,7 +4455,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.umin" = .{ .ret_len = 1, @@ -3668,7 +4463,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmax" = .{ .ret_len = 1, @@ -3676,7 +4471,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmin" = .{ .ret_len = 1, @@ -3684,7 +4479,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmaximum" = .{ .ret_len = 1, @@ -3692,7 +4487,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fminimum" = .{ .ret_len = 1, @@ -3700,7 +4495,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.insert" = .{ .ret_len = 1, @@ -3710,7 +4505,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i64 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.extract" = .{ .ret_len = 1, @@ -3719,7 +4514,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i64 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"is.fpclass" = .{ @@ -3729,7 +4524,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"var.annotation" = .{ @@ -3814,7 +4609,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .expect = .{ .ret_len = 1, @@ -3823,7 +4618,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"expect.with.probability" = .{ .ret_len = 1, @@ -3833,7 +4628,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .assume = .{ .ret_len = 0, @@ -3848,7 +4643,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.test" = .{ .ret_len = 1, @@ -3857,7 +4652,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .ptr } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.checked.load" = .{ .ret_len = 2, @@ -3868,7 +4663,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.checked.load.relative" = .{ .ret_len = 2, @@ -3879,7 +4674,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"arithmetic.fence" = .{ .ret_len = 1, @@ -3887,12 +4682,12 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .donothing = .{ .ret_len = 0, .params = &.{}, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"load.relative" = .{ .ret_len = 1, @@ -3914,7 +4709,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .ptrmask = .{ .ret_len = 1, @@ -3923,7 +4718,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"threadlocal.address" = .{ .ret_len = 1, @@ -3931,14 +4726,14 @@ pub const Intrinsic = enum { .{ .kind = .overloaded, .attrs = &.{.nonnull} }, .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .vscale = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"dbg.declare" = .{ @@ -3948,7 +4743,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .metadata } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"dbg.value" = .{ .ret_len = 0, @@ -3957,7 +4752,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .metadata } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.x" = .{ @@ -3965,42 +4760,42 @@ pub const Intrinsic = enum { .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.y" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.z" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.x" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.y" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.z" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.dispatch.ptr" = .{ .ret_len = 1, @@ -4010,7 +4805,7 @@ pub const Intrinsic = enum { .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }}, }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"nvvm.read.ptx.sreg.tid.x" = .{ @@ -4085,7 +4880,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"wasm.memory.grow" = .{ .ret_len = 1, @@ -4166,6 +4961,10 @@ pub const Function = struct { self.ptr(builder).attributes = new_function_attributes; } + pub fn getAttributes(self: Index, builder: *Builder) FunctionAttributes { + return self.ptr(builder).attributes; + } + pub fn setSection(self: Index, section: String, builder: *Builder) void { self.ptr(builder).section = section; } @@ -4487,7 +5286,7 @@ pub const Function = struct { } pub fn toValue(self: Instruction.Index) Value { - return @fromBackingInt(@intCast(@backingInt(self))); + return @fromBackingInt(@backingInt(self)); } pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool { @@ -4679,7 +5478,7 @@ pub const Function = struct { .changeScalarAssumeCapacity(.i1, wip.builder), .fneg, .@"fneg fast", - => @as(Value, @fromBackingInt(@intCast(instruction.data))).typeOfWip(wip), + => @as(Value, @fromBackingInt(instruction.data)).typeOfWip(wip), .getelementptr, .@"getelementptr inbounds", => { @@ -4871,7 +5670,7 @@ pub const Function = struct { .changeScalarAssumeCapacity(.i1, builder), .fneg, .@"fneg fast", - => @as(Value, @fromBackingInt(@intCast(instruction.data))).typeOf(function_index, builder), + => @as(Value, @fromBackingInt(instruction.data)).typeOf(function_index, builder), .getelementptr, .@"getelementptr inbounds", => { @@ -4963,7 +5762,7 @@ pub const Function = struct { pub fn fromMetadata(metadata: Metadata) Weights { assert(metadata.kind == .node); - return @fromBackingInt(@intCast(metadata.index)); + return @fromBackingInt(metadata.index); } pub fn toMetadata(weights: Weights) Metadata { @@ -5156,7 +5955,7 @@ pub const Function = struct { assert(argument.tag == .arg); assert(argument.data == index); - const argument_index: Instruction.Index = @fromBackingInt(@intCast(index)); + const argument_index: Instruction.Index = @fromBackingInt(index); return argument_index.toValue(); } @@ -5202,7 +6001,7 @@ pub const Function = struct { Type, Value, Instruction.BrCond.Weights, - => @fromBackingInt(@intCast(value)), + => @fromBackingInt(value), MemoryAccessInfo, Instruction.Alloca.Info, Instruction.Call.Info, @@ -5327,7 +6126,7 @@ pub const WipFunction = struct { assert(argument.tag == .arg); assert(argument.data == index); - const argument_index: Instruction.Index = @fromBackingInt(@intCast(index)); + const argument_index: Instruction.Index = @fromBackingInt(index); return argument_index.toValue(); } @@ -5722,7 +6521,7 @@ pub const WipFunction = struct { alignment: Alignment, name: []const u8, ) Allocator.Error!Value { - return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name); + return self.loadAtomic(access_kind, ty, ptr, undefined, .none, alignment, name); } pub fn loadAtomic( @@ -5766,7 +6565,7 @@ pub const WipFunction = struct { ptr: Value, alignment: Alignment, ) Allocator.Error!Instruction.Index { - return self.storeAtomic(kind, val, ptr, .system, .none, alignment); + return self.storeAtomic(kind, val, ptr, undefined, .none, alignment); } pub fn storeAtomic( @@ -6414,24 +7213,24 @@ pub const WipFunction = struct { errdefer function.instructions.shrinkRetainingCapacity(0); { - var final_instruction_index: Instruction.Index = @fromBackingInt(@intCast(0)); + var final_instruction_index: Instruction.Index = @fromBackingInt(0); for (0..params_len) |param_index| { instructions.items[param_index] = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); } for (blocks, self.blocks.items) |*final_block, current_block| { assert(current_block.incoming == current_block.branches); final_block.instruction = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); for (current_block.instructions.items) |instruction| { instructions.items[@backingInt(instruction)] = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); } } } var wip_name: struct { - next_name: String = @fromBackingInt(@intCast(0)), + next_name: String = @fromBackingInt(0), next_unique_name: std.AutoHashMap(String, String), builder: *Builder, @@ -6440,19 +7239,19 @@ pub const WipFunction = struct { .none => return .none, .empty => { assert(wip_name.next_name != .none); - defer wip_name.next_name = @fromBackingInt(@intCast(@backingInt(wip_name.next_name) + 1)); + defer wip_name.next_name = @fromBackingInt(@backingInt(wip_name.next_name) + 1); return wip_name.next_name; }, _ => { assert(!name.isAnon()); const gop = try wip_name.next_unique_name.getOrPut(name); if (!gop.found_existing) { - gop.value_ptr.* = @fromBackingInt(@intCast(0)); + gop.value_ptr.* = @fromBackingInt(0); return name; } while (true) { - gop.value_ptr.* = @fromBackingInt(@intCast(@backingInt(gop.value_ptr.*) + 1)); + gop.value_ptr.* = @fromBackingInt(@backingInt(gop.value_ptr.*) + 1); const unique_name = try wip_name.builder.fmt("{f}{s}{f}", .{ name.fmtRaw(wip_name.builder), sep, @@ -6460,7 +7259,7 @@ pub const WipFunction = struct { }); const unique_gop = try wip_name.next_unique_name.getOrPut(unique_name); if (!unique_gop.found_existing) { - unique_gop.value_ptr.* = @fromBackingInt(@intCast(0)); + unique_gop.value_ptr.* = @fromBackingInt(0); return unique_name; } } @@ -6702,7 +7501,7 @@ pub const WipFunction = struct { .fneg, .@"fneg fast", .ret, - => instruction.data = @backingInt(instructions.map(@fromBackingInt(@intCast(instruction.data)))), + => instruction.data = @backingInt(instructions.map(@fromBackingInt(instruction.data))), .getelementptr, .@"getelementptr inbounds", => { @@ -7079,7 +7878,7 @@ pub const WipFunction = struct { Type, Value, Instruction.BrCond.Weights, - => @fromBackingInt(@intCast(value)), + => @fromBackingInt(value), MemoryAccessInfo, Instruction.Alloca.Info, Instruction.Call.Info, @@ -7268,7 +8067,7 @@ pub const Constant = enum(u32) { no_init = (1 << 30) - 1, _, - const first_global: Constant = @fromBackingInt(@intCast(1 << 29)); + const first_global: Constant = @fromBackingInt(1 << 29); pub const Tag = enum(u7) { positive_integer, @@ -7405,7 +8204,18 @@ pub const Constant = enum(u32) { val: Constant, type: Type, - pub const Signedness = enum { unsigned, signed, unneeded }; + pub const Signedness = enum { + unsigned, + signed, + unneeded, + + pub fn fromStdLang(signedness: std.lang.Signedness) Signedness { + return switch (signedness) { + .unsigned => .unsigned, + .signed => .signed, + }; + } + }; }; pub const GetElementPtr = struct { @@ -7444,11 +8254,11 @@ pub const Constant = enum(u32) { return if (@backingInt(self) < @backingInt(first_global)) .{ .constant = @intCast(@backingInt(self)) } else - .{ .global = @fromBackingInt(@intCast(@backingInt(self) - @backingInt(first_global))) }; + .{ .global = @fromBackingInt(@backingInt(self) - @backingInt(first_global)) }; } pub fn toValue(self: Constant) Value { - return @fromBackingInt(@intCast(Value.first_constant + @backingInt(self))); + return @fromBackingInt(Value.first_constant + @backingInt(self)); } pub fn typeOf(self: Constant, builder: *Builder) Type { @@ -7474,7 +8284,7 @@ pub const Constant = enum(u32) { .zeroinitializer, .undef, .poison, - => @fromBackingInt(@intCast(item.data)), + => @fromBackingInt(item.data), .structure, .packed_structure, .array, @@ -7482,7 +8292,7 @@ pub const Constant = enum(u32) { => builder.constantExtraData(Aggregate, item.data).type, .splat => builder.constantExtraData(Splat, item.data).type, .string => builder.arrayTypeAssumeCapacity( - @as(String, @fromBackingInt(@intCast(item.data))).slice(builder).?.len, + @as(String, @fromBackingInt(item.data)).slice(builder).?.len, .i8, ), .blockaddress => builder.ptrTypeAssumeCapacity( @@ -7491,7 +8301,7 @@ pub const Constant = enum(u32) { ), .dso_local_equivalent, .no_cfi, - => builder.ptrTypeAssumeCapacity(@as(Function.Index, @fromBackingInt(@intCast(item.data))) + => builder.ptrTypeAssumeCapacity(@as(Function.Index, @fromBackingInt(item.data)) .ptrConst(builder).global.ptrConst(builder).addr_space), .trunc, .ptrtoint, @@ -7802,7 +8612,7 @@ pub const Constant = enum(u32) { try w.writeByte('>'); }, .string => try w.print("c{f}", .{ - @as(String, @fromBackingInt(@intCast(item.data))).fmtQ(data.builder), + @as(String, @fromBackingInt(item.data)).fmtQ(data.builder), }), .blockaddress => |tag| { const extra = data.builder.constantExtraData(BlockAddress, item.data); @@ -7816,7 +8626,7 @@ pub const Constant = enum(u32) { .dso_local_equivalent, .no_cfi, => |tag| { - const function: Function.Index = @fromBackingInt(@intCast(item.data)); + const function: Function.Index = @fromBackingInt(item.data); try w.print("{s} {f}", .{ @tagName(tag), function.ptrConst(data.builder).global.fmt(data.builder), @@ -7920,9 +8730,9 @@ pub const Value = enum(u32) { metadata: Metadata, } { return if (@backingInt(self) < first_constant) - .{ .instruction = @fromBackingInt(@intCast(@backingInt(self))) } + .{ .instruction = @fromBackingInt(@backingInt(self)) } else if (@backingInt(self) < first_metadata) - .{ .constant = @fromBackingInt(@intCast(@backingInt(self) - first_constant)) } + .{ .constant = @fromBackingInt(@backingInt(self) - first_constant) } else .{ .metadata = @bitCast(@backingInt(self) - first_metadata) }; } @@ -8016,7 +8826,7 @@ pub const Metadata = packed struct(u32) { return .{ .index = metadata.index, .kind = metadata.kind, .is_none = false }; } pub fn toValue(metadata: Metadata) Value { - return @fromBackingInt(@intCast(Value.first_metadata + @as(u32, @bitCast(metadata)))); + return @fromBackingInt(Value.first_metadata + @as(u32, @bitCast(metadata))); } pub const String = enum(u32) { @@ -8032,7 +8842,7 @@ pub const Metadata = packed struct(u32) { pub fn unwrap(metadata: Metadata.String.Optional) ?Metadata.String { return switch (metadata) { .none => null, - else => @fromBackingInt(@intCast(@backingInt(metadata))), + else => @fromBackingInt(@backingInt(metadata)), }; } pub fn toMetadata(metadata: Metadata.String.Optional) Metadata.Optional { @@ -8040,7 +8850,7 @@ pub const Metadata = packed struct(u32) { } }; pub fn toOptional(metadata: Metadata.String) Metadata.String.Optional { - return @fromBackingInt(@intCast(@backingInt(metadata))); + return @fromBackingInt(@backingInt(metadata)); } pub fn toMetadata(metadata: Metadata.String) Metadata { return .{ .index = @intCast(@backingInt(metadata)), .kind = .string }; @@ -8077,7 +8887,7 @@ pub const Metadata = packed struct(u32) { }; pub fn toString(metadata: Metadata) Metadata.String { assert(metadata.kind == .string); - return @fromBackingInt(@intCast(metadata.index)); + return @fromBackingInt(metadata.index); } pub const Tag = enum(u6) { @@ -8542,7 +9352,7 @@ pub const Metadata = packed struct(u32) { try w.writeByte(')'); }, .constant => try Constant.format(.{ - .constant = @fromBackingInt(@intCast(node_item.data)), + .constant = @fromBackingInt(node_item.data), .builder = builder, .flags = data.specialized orelse .{}, }, w), @@ -8735,7 +9545,14 @@ pub fn init(options: Options) Allocator.Error!Builder { .strip = options.strip, .source_filename = .none, - .data_layout = .none, + .data_layout = .{ + .endian = null, + .int_specs = .empty, + .float_specs = .empty, + .vector_specs = .empty, + .pointer_specs = .empty, + .string_repr = .none, + }, .target_triple = .none, .module_asm = .empty, @@ -8744,7 +9561,7 @@ pub fn init(options: Options) Allocator.Error!Builder { .string_bytes = .empty, .types = .empty, - .next_unnamed_type = @fromBackingInt(@intCast(0)), + .next_unnamed_type = @fromBackingInt(0), .next_unique_type_id = .empty, .type_map = .empty, .type_items = .empty, @@ -8758,7 +9575,7 @@ pub fn init(options: Options) Allocator.Error!Builder { .function_attributes_set = .empty, .globals = .empty, - .next_unnamed_global = @fromBackingInt(@intCast(0)), + .next_unnamed_global = @fromBackingInt(0), .next_replaced_global = .none, .next_unique_global_id = .empty, .aliases = .empty, @@ -8791,14 +9608,14 @@ pub fn init(options: Options) Allocator.Error!Builder { try self.string_indices.append(self.gpa, 0); assert(try self.string("") == .empty); + self.data_layout = try .parseString(try self.string(DataLayout.stringForTarget(options.target)), &self); + try self.strtab_string_indices.append(self.gpa, 0); assert(try self.strtabString("") == .empty); if (options.name.len > 0) self.source_filename = try self.string(options.name); - if (options.triple.len > 0) { - self.target_triple = try self.string(options.triple); - } + if (options.triple.len > 0) self.target_triple = try self.string(options.triple); { const static_len = @typeInfo(Type).@"enum".field_names.len - 1; @@ -8815,7 +9632,7 @@ pub fn init(options: Options) Allocator.Error!Builder { assert(self.intTypeAssumeCapacity(bits) == @field(Type, std.fmt.comptimePrint("i{d}", .{bits}))); inline for (.{ 0, 4 }) |addr_space_index| { - const addr_space: AddrSpace = @fromBackingInt(@intCast(addr_space_index)); + const addr_space: AddrSpace = @fromBackingInt(addr_space_index); assert(self.ptrTypeAssumeCapacity(addr_space) == @field(Type, std.fmt.comptimePrint("ptr{f}", .{addr_space.fmt(" ")}))); } @@ -8891,6 +9708,8 @@ pub fn clearAndFree(self: *Builder) void { pub fn deinit(self: *Builder) void { const gpa = self.gpa; + self.data_layout.deinit(gpa); + self.module_asm.deinit(gpa); self.string_map.deinit(gpa); @@ -9092,17 +9911,17 @@ pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attr return @backingInt(lhs_kind) < @backingInt(rhs_kind); } }.lessThan); - return @fromBackingInt(@intCast(try self.attrGeneric(@ptrCast(attributes)))); + return @fromBackingInt(try self.attrGeneric(@ptrCast(attributes))); } pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes { try self.function_attributes_set.ensureUnusedCapacity(self.gpa, 1); - const function_attributes: FunctionAttributes = @fromBackingInt(@intCast(try self.attrGeneric(@ptrCast( + const function_attributes: FunctionAttributes = @fromBackingInt(try self.attrGeneric(@ptrCast( fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last| last + 1 else 0], - )))); + ))); _ = self.function_attributes_set.getOrPutAssumeCapacity(function_attributes); return function_attributes; @@ -9121,7 +9940,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: StrtabString, global: Globa if (name == .empty) { id = self.next_unnamed_global; assert(id != self.next_replaced_global); - self.next_unnamed_global = @fromBackingInt(@intCast(@backingInt(id) + 1)); + self.next_unnamed_global = @fromBackingInt(@backingInt(id) + 1); } while (true) { const global_gop = self.globals.getOrPutAssumeCapacity(id); @@ -9710,17 +10529,17 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined }; defer metadata_formatter.map.deinit(self.gpa); - if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { + if (self.source_filename != .none or self.data_layout.string_repr != .none or self.target_triple != .none) { if (need_newline) try w.writeByte('\n') else need_newline = true; if (self.source_filename != .none) try w.print( \\; ModuleID = '{s}' \\source_filename = {f} \\ , .{ self.source_filename.slice(self).?, self.source_filename.fmtQ(self) }); - if (self.data_layout != .none) try w.print( + if (self.data_layout.string_repr != .none) try w.print( \\target datalayout = {f} \\ - , .{self.data_layout.fmtQ(self)}); + , .{self.data_layout.string_repr.fmtQ(self)}); if (self.target_triple != .none) try w.print( \\target triple = {f} \\ @@ -10058,7 +10877,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void continue; }, .br => |tag| { - const target: Function.Block.Index = @fromBackingInt(@intCast(instruction.data)); + const target: Function.Block.Index = @fromBackingInt(instruction.data); try w.print(" {s} {f}", .{ @tagName(tag), target.toInst(&function).fmt(function_index, self, .{ .percent = true }), }); @@ -10187,7 +11006,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .fneg, .@"fneg fast", => |tag| { - const val: Value = @fromBackingInt(@intCast(instruction.data)); + const val: Value = @fromBackingInt(instruction.data); try w.print(" %{f} = {s} {f}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), @@ -10288,7 +11107,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void } }, .ret => |tag| { - const val: Value = @fromBackingInt(@intCast(instruction.data)); + const val: Value = @fromBackingInt(instruction.data); try w.print(" {s} {f}", .{ @tagName(tag), val.fmt(function_index, self, .{ .percent = true }), @@ -11020,7 +11839,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { if (name == .empty) { id = self.next_unnamed_type; assert(id != .none); - self.next_unnamed_type = @fromBackingInt(@intCast(@backingInt(id) + 1)); + self.next_unnamed_type = @fromBackingInt(@backingInt(id) + 1); } else assert(!name.isAnon()); while (true) { const type_gop = self.types.getOrPutAssumeCapacity(id); @@ -11135,7 +11954,7 @@ fn typeExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - String, Type => @fromBackingInt(@intCast(value)), + String, Type => @fromBackingInt(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; return .{ @@ -11746,7 +12565,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: return std.meta.eql(lhs_key.cast, rhs_extra); } }; - const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } }; + const data: Key = .{ .tag = tag, .cast = .{ .val = val, .type = ty } }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); if (!gop.found_existing) { gop.key_ptr.* = {}; @@ -11828,10 +12647,10 @@ fn gepConstAssumeCapacity( std.mem.eql(Constant, lhs_key.indices, rhs_indices); } }; - const data = Key{ + const data: Key = .{ .type = ty, .base = base, - .inrange = if (inrange) |index| @fromBackingInt(@intCast(index)) else .none, + .inrange = if (inrange) |index| @fromBackingInt(index) else .none, .indices = indices, }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); @@ -11885,7 +12704,7 @@ fn binConstAssumeCapacity( return std.meta.eql(lhs_key.extra, rhs_extra); } }; - const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } }; + const data: Key = .{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); if (!gop.found_existing) { gop.key_ptr.* = {}; @@ -11924,8 +12743,8 @@ fn asmConstAssumeCapacity( } }; - const data = Key{ - .tag = @fromBackingInt(@intCast(@backingInt(Constant.Tag.@"asm") + @as(u4, @bitCast(info)))), + const data: Key = .{ + .tag = @fromBackingInt(@backingInt(Constant.Tag.@"asm") + @as(u4, @bitCast(info))), .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints }, }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); @@ -12073,7 +12892,7 @@ fn constantExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - String, Type, Constant, Function.Index, Function.Block.Index => @fromBackingInt(@intCast(value)), + String, Type, Constant, Function.Index, Function.Block.Index => @fromBackingInt(value), Constant.GetElementPtr.Info => @bitCast(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; @@ -12151,7 +12970,7 @@ fn metadataExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - Metadata.String, Metadata.String.Optional, Variable.Index, Value => @fromBackingInt(@intCast(value)), + Metadata.String, Metadata.String.Optional, Variable.Index, Value => @fromBackingInt(value), Metadata, Metadata.Optional, Metadata.DIFlags => @bitCast(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; @@ -12759,8 +13578,8 @@ fn debugSubprogramAssumeCapacity( compile_unit: ?Metadata, ) Metadata { assert(!self.strip); - const tag: Metadata.Tag = @fromBackingInt(@intCast(@backingInt(Metadata.Tag.subprogram) + - @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2)))); + const tag: Metadata.Tag = @fromBackingInt(@backingInt(Metadata.Tag.subprogram) + + @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2))); return self.metadataDistinctAssumeCapacity(tag, Metadata.Subprogram{ .file = .wrap(file), .name = .wrap(name), @@ -13345,7 +14164,7 @@ fn metadataConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata { pub fn eql(ctx: @This(), lhs_key: Constant, _: void, rhs_index: usize) bool { if (Metadata.Tag.constant != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false; - const rhs_data: Constant = @fromBackingInt(@intCast(ctx.builder.metadata_items.items(.data)[rhs_index])); + const rhs_data: Constant = @fromBackingInt(ctx.builder.metadata_items.items(.data)[rhs_index]); return rhs_data == lhs_key; } }; @@ -13418,7 +14237,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }); } - if (self.data_layout.slice(self)) |data_layout| { + if (self.data_layout.string_repr.slice(self)) |data_layout| { try module_block.writeAbbrev(ModuleBlock.String{ .code = 3, .string = data_layout, @@ -13577,6 +14396,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco switch (attr_index.toAttribute(self)) { .zeroext, .signext, + .noext, .inreg, .@"noalias", .nocapture, @@ -13594,11 +14414,13 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .readnone, .readonly, .writeonly, + .writable, + .dead_on_unwind, .alwaysinline, .builtin, .cold, .convergent, - .disable_sanitizer_information, + .disable_sanitizer_instrumentation, .fn_ret_thunk_extern, .hot, .inlinehint, @@ -13607,6 +14429,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .naked, .nobuiltin, .nocallback, + .nodivergencesource, .noduplicate, .noimplicitfloat, .@"noinline", @@ -13623,6 +14446,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .nosanitize_bounds, .nosanitize_coverage, .null_pointer_is_valid, + .optdebug, .optforfuzzing, .optnone, .optsize, @@ -13633,18 +14457,21 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .sanitize_thread, .sanitize_hwaddress, .sanitize_memtag, + .sanitize_realtime, + .sanitize_realtime_blocking, + .sanitize_alloc_token, .speculative_load_hardening, .speculatable, .ssp, .sspstrong, .sspreq, .strictfp, + .denormal_fpenv, .nocf_check, .shadowcallstack, .mustprogress, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, + .nooutline, + .nocreateundeforpoison, => { try record.ensureUnusedCapacity(self.gpa, 2); record.appendAssumeCapacity(0); @@ -13670,6 +14497,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco record.appendAssumeCapacity(@backingInt(kind)); record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0); }, + .captures => |captures| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@backingInt(kind)); + record.appendAssumeCapacity(@as(u32, @bitCast(captures))); + }, .dereferenceable, .dereferenceable_or_null, => |size| { @@ -13684,6 +14517,9 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco record.appendAssumeCapacity(@backingInt(kind)); record.appendAssumeCapacity(@as(u32, @bitCast(fpclass))); }, + .initializes => @panic("TODO"), + .dead_on_return => @panic("TODO"), + .range => @panic("TODO"), .allockind => |allockind| { try record.ensureUnusedCapacity(self.gpa, 3); record.appendAssumeCapacity(1); @@ -14099,7 +14935,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco } }, .string => { - const str: String = @fromBackingInt(@intCast(data)); + const str: String = @fromBackingInt(data); if (str == .none) { try constants_block.writeAbbrev(ConstantsBlock.Null{}); } else { @@ -14226,7 +15062,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .dso_local_equivalent, .no_cfi, => |tag| { - const function: Function.Index = @fromBackingInt(@intCast(data)); + const function: Function.Index = @fromBackingInt(data); try constants_block.writeAbbrev(ConstantsBlock.DsoLocalEquivalentOrNoCfi{ .code = switch (tag) { .dso_local_equivalent => .DSO_LOCAL_EQUIVALENT, @@ -14609,7 +15445,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }, metadata_adapter); }, .constant => { - const constant: Constant = @fromBackingInt(@intCast(data)); + const constant: Constant = @fromBackingInt(data); try metadata_block.writeAbbrevAdapted(MetadataBlock.Constant{ .ty = constant.typeOf(self), .constant = constant, @@ -14778,7 +15614,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco var adapter: FunctionAdapter = .{ .metadata_adapter = metadata_adapter, .func = &func, - .instruction_index = @fromBackingInt(@intCast(0)), + .instruction_index = @fromBackingInt(0), }; // Emit function level metadata block @@ -14789,7 +15625,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco for (func.debug_values) |value| { try metadata_block.writeAbbrev(MetadataBlock.Value{ .ty = value.typeOf(@fromBackingInt(@intCast(func_index)), self), - .value = @fromBackingInt(@intCast(adapter.getValueIndex(value.toValue()))), + .value = @fromBackingInt(adapter.getValueIndex(value.toValue())), }); } @@ -15071,10 +15907,10 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }); }, .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), }), .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), .fast_math = FastMath.fast, }), .extractvalue => { @@ -15274,7 +16110,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco try function_block.writeUnabbrev(16, record.items); }, .ret => try function_block.writeAbbrev(FunctionBlock.Ret{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), }), .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}), .atomicrmw => { diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig index 0ac83c50dc57047ff1a937182b717960b14e8f82..e30cae2a6728a7df71e9bef14f194f6264809604 100644 --- a/lib/std/zig/target.zig +++ b/lib/std/zig/target.zig @@ -499,34 +499,32 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 { } pub fn intAlignment(target: *const std.Target, bits: u16) u16 { - return switch (target.cpu.arch) { - .x86 => switch (bits) { - 0...8 => 1, - 9...16 => 2, - 17...32 => 4, - 33...64 => switch (target.os.tag) { - .uefi, .windows => 8, - else => 4, - }, - else => 16, - }, - .x86_64 => switch (bits) { - 0...8 => 1, - 9...16 => 2, - 17...32 => 4, - 33...64 => 8, - else => 16, - }, - else => switch (bits) { - 0 => 1, - else => @min( - std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)), - target.cMaxIntAlignment(), - ), - }, + return switch (bits) { + 0 => 1, + else => @min( + std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)), + target.cMaxIntAlignment(), + ), }; } +pub fn compilerRtFloatAbi(target: *const std.Target, bits: u16) std.Target.Abi.Float { + if (target.cpu.has(.x86, .soft_float)) return .soft; + // Marks targets where clang does not even provide a usable C type. + const no_c_type_available = .soft; + switch (bits) { + else => unreachable, + 16 => if (target.cpu.arch.isMIPS() or target.cpu.arch.isPowerPC()) return no_c_type_available, + 32, 64 => {}, + 80 => if (target.cTypeBitSize(.longdouble) != 80) return no_c_type_available, + 128 => { + if (target.cpu.arch.isX86()) return .hard; // if (target.abi == .msvc) __m128i else __float128 + if (target.cTypeBitSize(.longdouble) != 128) return no_c_type_available; + }, + } + return .hard; +} + const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index b22de08eacccf9c75e24a6f32e85ce7d795e12a8..16294f3df6d763df2587b48fbb99e3b6615d478f 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -9,7 +9,6 @@ //! For lower level control over parsing, see `std.zig.Zoir`. const std = @import("std"); -const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const Ast = std.zig.Ast; const Zoir = std.zig.Zoir; @@ -1868,8 +1867,6 @@ test "std.zon tuples" { // Test sizes 0 to 3 since small sizes get parsed differently test "std.zon arrays and slices" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/20881 - const gpa = std.testing.allocator; // Literals @@ -2802,8 +2799,6 @@ test "std.zon negative char" { } test "std.zon parse float" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - const gpa = std.testing.allocator; // Test decimals @@ -3135,7 +3130,7 @@ test "std.zon free on error" { } test "std.zon vector" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/15330 + const builtin = @import("builtin"); if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25957 const gpa = std.testing.allocator; diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index 57b62d41cac6c3f9aa0e442bd276edb33f2679c2..a1c6b39ebe25a350d08eba57008fbd3522c16f76 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -1151,9 +1151,6 @@ test "std.zon depth limits" { } test "std.zon stringify primitives" { - // Issue: https://github.com/ziglang/zig/issues/20880 - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - try expectSerializeEqual( \\.{ \\ .a = 1.5, diff --git a/lib/zig.h b/lib/zig.h index fbc924ca334e99eb12d2f37e3ebffa970ced7b9d..30e6f3f96a97f47b6648db1d1587bc75c88b6c3f 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -166,6 +166,12 @@ #endif #define zig_expand_has_builtin(b) zig_has_builtin(b) +#if defined(__has_feature) +#define zig_has_feature(feature) __has_feature(feature) +#else +#define zig_has_feature(feature) 0 +#endif + #if defined(__has_attribute) #define zig_has_attribute(attribute) __has_attribute(attribute) #else @@ -175,9 +181,9 @@ #if __STDC_VERSION__ >= 201112L #define zig_static_assert(cond, msg) _Static_assert(cond, msg) #elif zig_has_attribute(unused) -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused)) +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] __attribute__((unused)) #else -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] #endif #if __STDC_VERSION__ >= 202311L @@ -193,10 +199,8 @@ #endif #if defined(zig_msvc) -#define zig_const_arr #define zig_callconv(c) __##c #else -#define zig_const_arr static const #define zig_callconv(c) __attribute__((c)) #endif @@ -267,12 +271,20 @@ #if __STDC_VERSION__ >= 202311L #define zig_align(alignment) alignas(alignment) -#elif __STDC_VERSION__ >= 201112L +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignas) #define zig_align(alignment) _Alignas(alignment) #else #define zig_align(alignment) zig_under_align(alignment) #endif +#if __STDC_VERSION__ >= 202311L +#define zig_alignOf(Type) alignof(Type) +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignof) +#define zig_alignOf(Type) _Alignof(Type) +#else +#define zig_alignOf(Type) (sizeof(struct { char c; Type t; }) - sizeof(Type)) +#endif + #if zig_has_attribute(aligned) || defined(zig_tinyc) #define zig_align_fn(alignment) __attribute__((aligned(alignment))) #elif defined(zig_msvc) @@ -350,11 +362,9 @@ #define zig_export(symbol, name) __attribute__((alias(symbol))) #else #define zig_export(symbol, name) ; \ - __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) + __asm("\t.globl\t" zig_mangle_c(name) "\n" zig_mangle_c(name) " = " zig_mangle_c(symbol)) #endif -#define zig_mangled_tentative zig_mangled -#define zig_mangled_final zig_mangled #if defined(zig_msvc) #define zig_mangled(mangled, unmangled) ; \ zig_export(#mangled, unmangled) @@ -364,7 +374,7 @@ #else /* zig_msvc */ #define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled)) #define zig_mangled_export(mangled, unmangled, symbol) \ - zig_mangled_final(mangled, unmangled) \ + zig_mangled(mangled, unmangled) \ zig_export(symbol, unmangled) #endif /* zig_msvc */ @@ -550,6 +560,9 @@ #define zig_noreturn #endif +#define zig_has_always 1 +#define zig_has_never 0 + #define zig_compiler_rt_abbrev_uint32_t si #define zig_compiler_rt_abbrev_int32_t si #define zig_compiler_rt_abbrev_uint64_t di @@ -560,7 +573,11 @@ #define zig_compiler_rt_abbrev_zig_f32 sf #define zig_compiler_rt_abbrev_zig_f64 df #define zig_compiler_rt_abbrev_zig_f80 xf +#ifdef zig_powerpc +#define zig_compiler_rt_abbrev_zig_f128 kf +#else #define zig_compiler_rt_abbrev_zig_f128 tf +#endif zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t); zig_extern void *memset (void *, int, size_t); @@ -645,16 +662,6 @@ typedef signed long long int16_t; #define INT16_MAX ( INT16_C(0x7FFF)) #define UINT16_MAX ( INT16_C(0xFFFF)) -#if defined(zig_ez80) -typedef unsigned int uint24_t; -typedef signed int int24_t; -#define INT24_C(c) c -#define UINT24_C(c) c##U -#endif -#define INT24_MIN (~INT24_C(0x7FFF)) -#define INT24_MAX ( INT24_C(0x7FFF)) -#define UINT24_MAX ( INT24_C(0xFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF typedef unsigned char uint32_t; typedef signed char int32_t; @@ -685,17 +692,6 @@ typedef signed long long int32_t; #define INT32_MAX ( INT32_C(0x7FFFFFFF)) #define UINT32_MAX ( INT32_C(0xFFFFFFFF)) -#if defined(zig_ez80) -typedef unsigned __int48 uint48_t; -typedef signed __int48 int48_t; -#define INT48_C(c) c -/* no suffix */ -#define UINT48_C(c) ((uint48_t)(c)) -#endif -#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) -#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) -#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF typedef unsigned char uint64_t; typedef signed char int64_t; @@ -726,6 +722,27 @@ typedef signed long long int64_t; #define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF)) #define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF)) +#if defined(zig_ez80) + +typedef unsigned int uint24_t; +typedef signed int int24_t; +#define INT24_C(c) c +#define UINT24_C(c) c##U +#define INT24_MIN (~INT24_C(0x7FFF)) +#define INT24_MAX ( INT24_C(0x7FFF)) +#define UINT24_MAX ( INT24_C(0xFFFF)) + +typedef unsigned __int48 uint48_t; +typedef signed __int48 int48_t; +#define INT48_C(c) c +/* no suffix */ +#define UINT48_C(c) ((uint48_t)(c)) +#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) +#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) +#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) + +#endif + typedef size_t uintptr_t; typedef ptrdiff_t intptr_t; @@ -739,23 +756,145 @@ typedef ptrdiff_t intptr_t; #define zig_maxInt_i16 INT16_MAX #define zig_minInt_u16 UINT16_C(0) #define zig_maxInt_u16 UINT16_MAX -#define zig_minInt_i24 INT24_MIN -#define zig_maxInt_i24 INT24_MAX -#define zig_minInt_u24 UINT24_C(0) -#define zig_maxInt_u24 UINT24_MAX #define zig_minInt_i32 INT32_MIN #define zig_maxInt_i32 INT32_MAX #define zig_minInt_u32 UINT32_C(0) #define zig_maxInt_u32 UINT32_MAX -#define zig_minInt_i48 INT48_MIN -#define zig_maxInt_i48 INT48_MAX -#define zig_minInt_u48 UINT48_C(0) -#define zig_maxInt_u48 UINT48_MAX #define zig_minInt_i64 INT64_MIN #define zig_maxInt_i64 INT64_MAX #define zig_minInt_u64 UINT64_C(0) #define zig_maxInt_u64 UINT64_MAX +// zig_promoted_T implements C integral promotions except with signedness preserved, which +// allows wrapping operations to avoid the ub that would be caused by the normal promotion. + +#if INT8_MAX <= INT_MAX +typedef unsigned int zig_promoted_i8; +#elif INT8_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i8; +#elif INT8_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i8; +#else +typedef int8_t zig_promoted_i8; +#endif +#if UINT8_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u8; +#elif UINT8_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u8; +#elif UINT8_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u8; +#else +typedef uint8_t zig_promoted_u8; +#endif + +#if INT16_MAX <= INT_MAX +typedef unsigned int zig_promoted_i16; +#elif INT16_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i16; +#elif INT16_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i16; +#else +typedef int16_t zig_promoted_i16; +#endif +#if UINT16_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u16; +#elif UINT16_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u16; +#elif UINT16_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u16; +#else +typedef uint16_t zig_promoted_u16; +#endif + +#if INT32_MAX <= INT_MAX +typedef unsigned int zig_promoted_i32; +#elif INT32_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i32; +#elif INT32_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i32; +#else +typedef int32_t zig_promoted_i32; +#endif +#if UINT32_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u32; +#elif UINT32_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u32; +#elif UINT32_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u32; +#else +typedef uint32_t zig_promoted_u32; +#endif + +#if INT64_MAX <= INT_MAX +typedef unsigned int zig_promoted_i64; +#elif INT64_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i64; +#elif INT64_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i64; +#else +typedef int64_t zig_promoted_i64; +#endif +#if UINT64_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u64; +#elif UINT64_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u64; +#elif UINT64_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u64; +#else +typedef uint64_t zig_promoted_u64; +#endif + +#ifdef zig_ez80 + +#define zig_minInt_i24 INT24_MIN +#define zig_maxInt_i24 INT24_MAX +#define zig_minInt_u24 UINT24_C(0) +#define zig_maxInt_u24 UINT24_MAX +#define zig_minInt_i48 INT48_MIN +#define zig_maxInt_i48 INT48_MAX +#define zig_minInt_u48 UINT48_C(0) +#define zig_maxInt_u48 UINT48_MAX + +#if INT24_MAX <= INT_MAX +typedef unsigned int zig_promoted_i24; +#elif INT24_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i24; +#elif INT24_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i24; +#else +typedef int24_t zig_promoted_i24; +#endif +#if UINT24_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u24; +#elif UINT24_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u24; +#elif UINT24_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u24; +#else +typedef uint24_t zig_promoted_u24; +#endif + +#if INT48_MAX <= INT_MAX +typedef unsigned int zig_promoted_i48; +#elif INT48_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i48; +#elif INT48_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i48; +#else +typedef int48_t zig_promoted_i48; +#endif +#if UINT48_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u48; +#elif UINT48_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u48; +#elif UINT48_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u48; +#else +typedef uint48_t zig_promoted_u48; +#endif + +#endif + #define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits)) #define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits) #define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits) @@ -770,7 +909,33 @@ typedef ptrdiff_t intptr_t; zig_operator(Type, Type, operation, operator) #define zig_shift_operator(Type, operation, operator) \ zig_operator(Type, uint8_t, operation, operator) -#define zig_int_helpers(w, PromotedUnsigned) \ + +#define zig_int_casts_common(bw, sw) \ + static inline uint##bw##_t zig_u##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##bw##_t zig_u##bw##_intCast_i##sw(int##sw##_t arg) { \ + return (uint##bw##_t)arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_i##sw(int##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_truncate_u##bw(uint##bw##_t arg, uint8_t bits) { \ + return (uint##sw##_t)arg & zig_maxInt_u(sw, bits); \ + } \ +\ + static inline int##sw##_t zig_i##sw##_truncate_i##bw(int##bw##_t arg, uint8_t bits) { \ + return ((uint##sw##_t)arg & UINT##sw##_C(1) << (bits - UINT8_C(1))) != UINT##sw##_C(0) \ + ? (int##sw##_t)arg | zig_minInt_i(sw, bits) : (int##sw##_t)arg & zig_maxInt_i(sw, bits); \ + } +#define zig_int_operators(w) \ zig_basic_operator(uint##w##_t, and_u##w, &) \ zig_basic_operator( int##w##_t, and_i##w, &) \ zig_basic_operator(uint##w##_t, or_u##w, |) \ @@ -786,44 +951,48 @@ typedef ptrdiff_t intptr_t; return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ } \ \ - static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \ - return val ^ zig_maxInt_u(w, bits); \ + static inline uint##w##_t zig_not_u##w(uint##w##_t arg, uint8_t bits) { \ + return arg ^ zig_maxInt_u(w, bits); \ } \ \ - static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \ + static inline int##w##_t zig_not_i##w(int##w##_t arg, uint8_t bits) { \ (void)bits; \ - return ~val; \ + return ~arg; \ } \ \ - static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \ - return val & zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \ - return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \ - ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_abs_i##w(int##w##_t val) { \ - return (val < 0) ? -(uint##w##_t)val : (uint##w##_t)val; \ - } \ -\ - zig_basic_operator(uint##w##_t, div_floor_u##w, /) \ + zig_basic_operator(uint##w##_t, divFloor_u##w, /) \ \ - static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divFloor_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ } \ \ - static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + static inline uint##w##_t zig_divCeil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ } \ \ - static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divCeil_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ } \ \ zig_basic_operator(uint##w##_t, mod_u##w, %) \ + zig_int_casts_common(w, w) \ +\ + static inline uint##w##_t zig_u##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w(arg, bits); \ + } \ +\ + static inline uint##w##_t zig_u##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_u##w##_bitCast_u##w((uint##w##_t)arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w(arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_i##w##_bitCast_i##w((int##w##_t)arg, bits); \ + } \ \ static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \ int##w##_t rem = lhs % rhs; \ @@ -831,100 +1000,102 @@ typedef ptrdiff_t intptr_t; } \ \ static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ + return zig_u##w##_truncate_u##w(zig_shl_u##w(lhs, rhs), bits); \ } \ \ static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_shl_u##w(zig_u##w##_bitCast_i##w(lhs, bits), rhs), bits); \ } \ \ static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs + rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs + rhs, bits); \ } \ \ static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_addw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs - rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs - rhs, bits); \ } \ \ static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_subw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs * rhs, bits); \ } \ \ static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_mulw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ + } \ +\ + static inline uint##w##_t zig_abs_i##w(int##w##_t arg) { \ + int##w##_t tmp = zig_shr_i##w(arg, UINT8_C(w) - UINT8_C(1)); \ + return zig_u##w##_bitCast_i##w(zig_subw_i##w(zig_xor_i##w(arg, tmp), tmp, UINT8_C(w)), UINT8_C(w)); \ + } \ +\ + static inline uint##w##_t zig_min_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_min_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline uint##w##_t zig_max_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_max_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ } -#if UINT8_MAX <= UINT_MAX -zig_int_helpers(8, unsigned int) -#elif UINT8_MAX <= ULONG_MAX -zig_int_helpers(8, unsigned long) -#elif UINT8_MAX <= ULLONG_MAX -zig_int_helpers(8, unsigned long long) -#else -zig_int_helpers(8, uint8_t) +zig_int_operators(8) +zig_int_operators(16) +zig_int_operators(32) +zig_int_operators(64) +#ifdef zig_ez80 +zig_int_operators(24) +zig_int_operators(48) #endif -#if UINT16_MAX <= UINT_MAX -zig_int_helpers(16, unsigned int) -#elif UINT16_MAX <= ULONG_MAX -zig_int_helpers(16, unsigned long) -#elif UINT16_MAX <= ULLONG_MAX -zig_int_helpers(16, unsigned long long) -#else -zig_int_helpers(16, uint16_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(24, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(24, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(24, unsigned long long) -#else -zig_int_helpers(24, uint24_t) -#endif -#endif -#if UINT32_MAX <= UINT_MAX -zig_int_helpers(32, unsigned int) -#elif UINT32_MAX <= ULONG_MAX -zig_int_helpers(32, unsigned long) -#elif UINT32_MAX <= ULLONG_MAX -zig_int_helpers(32, unsigned long long) -#else -zig_int_helpers(32, uint32_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(48, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(48, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(48, unsigned long long) -#else -zig_int_helpers(48, uint48_t) -#endif -#endif -#if UINT64_MAX <= UINT_MAX -zig_int_helpers(64, unsigned int) -#elif UINT64_MAX <= ULONG_MAX -zig_int_helpers(64, unsigned long) -#elif UINT64_MAX <= ULLONG_MAX -zig_int_helpers(64, unsigned long long) -#else -zig_int_helpers(64, uint64_t) + +#define zig_int_casts(bw, sw) \ + static inline uint##sw##_t zig_u##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + zig_int_casts_common(bw, sw) +zig_int_casts(16, 8) +zig_int_casts(32, 8) +zig_int_casts(64, 8) +zig_int_casts(32, 16) +zig_int_casts(64, 16) +zig_int_casts(64, 32) +#ifdef zig_ez80 +zig_int_casts(32, 24) +zig_int_casts(48, 24) +zig_int_casts(64, 24) +zig_int_casts(64, 48) #endif static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_addw_u32(lhs, rhs, bits); @@ -936,19 +1107,19 @@ static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs + (uint32_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i32(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_addw_u64(lhs, rhs, bits); @@ -960,24 +1131,24 @@ static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs + (uint64_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i64(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -986,12 +1157,12 @@ static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(add_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1000,12 +1171,12 @@ static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1014,27 +1185,28 @@ static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_addo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1043,28 +1215,26 @@ static inline bool zig_addo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_addo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_addo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1073,22 +1243,23 @@ static inline bool zig_addo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_addo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_subw_u32(lhs, rhs, bits); @@ -1100,20 +1271,19 @@ static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs - (uint32_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i32(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } - static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_subw_u64(lhs, rhs, bits); @@ -1125,24 +1295,24 @@ static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs - (uint64_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i64(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1151,12 +1321,12 @@ static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1165,12 +1335,12 @@ static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1179,27 +1349,28 @@ static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_subo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1208,28 +1379,26 @@ static inline bool zig_subo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_subo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_subo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1238,22 +1407,23 @@ static inline bool zig_subo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_subo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_mulw_u32(lhs, rhs, bits); @@ -1261,8 +1431,8 @@ static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8 #endif } -zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { + zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1271,7 +1441,7 @@ static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t int32_t full_res = __mulosi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i32(full_res, bits); + *res = zig_i32_truncate_i32(full_res, bits); return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } @@ -1279,7 +1449,7 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_mulw_u64(lhs, rhs, bits); @@ -1287,8 +1457,8 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #endif } -zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { + zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1297,7 +1467,7 @@ static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t int64_t full_res = __mulodi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i64(full_res, bits); + *res = zig_i64_truncate_i64(full_res, bits); return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } @@ -1305,12 +1475,12 @@ static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t b #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1319,12 +1489,12 @@ static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1333,12 +1503,12 @@ static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1347,27 +1517,28 @@ static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_mulo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1376,28 +1547,26 @@ static inline bool zig_mulo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_mulo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_mulo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1406,18 +1575,32 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_mulo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif -#define zig_int_builtins(w) \ +#define zig_shls_builtins(lw, rw) \ + static inline uint##lw##_t zig_shls_u##lw##_u##rw(uint##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + uint##lw##_t res; \ + if (rhs < bits && !zig_shlo_u##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? zig_minInt_u(lw, bits) : zig_maxInt_u(lw, bits); \ + } \ +\ + static inline int##lw##_t zig_shls_i##lw##_u##rw(int##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + int##lw##_t res; \ + if (rhs < bits && !zig_shlo_i##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? INT##lw##_C(0) : \ + lhs < INT##lw##_C(0) ? zig_minInt_i(lw, bits) : zig_maxInt_i(lw, bits); \ + } +#define zig_int_sat_builtins(w) \ static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ return lhs > zig_maxInt_u(w, bits) >> rhs; \ @@ -1429,18 +1612,10 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \ } \ \ - static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - if (rhs < bits && !zig_shlo_u##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_shls_i##w(int##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (rhs < bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ - lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ + zig_shls_builtins(w, 8) \ + zig_shls_builtins(w, 16) \ + zig_shls_builtins(w, 32) \ + zig_shls_builtins(w, 64) \ \ static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ uint##w##_t res; \ @@ -1474,332 +1649,321 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ } -zig_int_builtins(8) -zig_int_builtins(16) +zig_int_sat_builtins(8) +zig_int_sat_builtins(16) +zig_int_sat_builtins(32) +zig_int_sat_builtins(64) #if defined(zig_ez80) -zig_int_builtins(24) +zig_int_sat_builtins(24) +zig_int_sat_builtins(48) #endif -zig_int_builtins(32) -#if defined(zig_ez80) -zig_int_builtins(48) -#endif -zig_int_builtins(64) -#define zig_builtin8(name, val) __builtin_##name(val) +#define zig_builtin8(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin8; -#define zig_builtin16(name, val) __builtin_##name(val) +#define zig_builtin16(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin16; -#if defined(zig_ez80) -#define zig_builtin24(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin24; -#endif - #if INT_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name(val) +#define zig_builtin32(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin32; #elif LONG_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name##l(val) +#define zig_builtin32(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin32; #endif -#if defined(zig_ez80) -#define zig_builtin48(name, val) __builtin_##name(val) -typedef unsigned long long zig_Builtin48; -#endif - #if INT_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name(val) +#define zig_builtin64(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin64; #elif LONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##l(val) +#define zig_builtin64(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin64; #elif LLONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##ll(val) +#define zig_builtin64(name, arg) __builtin_##name##ll(arg) typedef unsigned long long zig_Builtin64; #endif -static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { - return zig_wrap_u8(val >> (8 - bits), bits); +#if defined(zig_ez80) +#define zig_builtin24(name, arg) __builtin_##name(arg) +typedef unsigned int zig_Builtin24; +#define zig_builtin48(name, arg) __builtin_##name(arg) +typedef unsigned long long zig_Builtin48; +#endif + +static inline uint8_t zig_byteSwap_u8(uint8_t arg, uint8_t bits) { + return zig_u8_truncate_u8(arg >> (8 - bits), bits); } -static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits); +static inline int8_t zig_byteSwap_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_byteSwap_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bswap16) || defined(zig_gcc) - full_res = __builtin_bswap16(val); + full_res = __builtin_bswap16(arg); #else - full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits); +static inline int16_t zig_byteSwap_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_byteSwap_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint16_t zig_byte_swap_u24(uint24_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bswap24) || defined(zig_gcc) - full_res = __builtin_bswap24(val); + full_res = __builtin_bswap24(arg); #else - full_res = (uint24_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_byte_swap_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_byteSwap_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int16_t zig_byte_swap_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_byte_swap_u24((uint24_t)val, bits), bits); +static inline int16_t zig_byteSwap_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_byteSwap_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bswap32) || defined(zig_gcc) - full_res = __builtin_bswap32(val); + full_res = __builtin_bswap32(arg); #else - full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits); +static inline int32_t zig_byteSwap_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_byteSwap_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_byte_swap_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bswap48) || defined(zig_gcc) - full_res = __builtin_bswap48(val); + full_res = __builtin_bswap48(arg); #else - full_res = (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u48(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_byte_swap_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_byte_swap_u48((uint48_t)val, bits), bits); +static inline int32_t zig_byteSwap_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_byteSwap_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_byteSwap_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bswap64) || defined(zig_gcc) - full_res = __builtin_bswap64(val); + full_res = __builtin_bswap64(arg); #else - full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits); +static inline int64_t zig_byteSwap_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_byteSwap_u64((uint64_t)arg, bits), bits); } -static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) { +static inline uint8_t zig_bitReverse_u8(uint8_t arg, uint8_t bits) { uint8_t full_res; #if zig_has_builtin(bitreverse8) - full_res = __builtin_bitreverse8(val); + full_res = __builtin_bitreverse8(arg); #else static uint8_t const lut[0x10] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; + full_res = lut[arg >> 0 & 0xF] << 4 | lut[arg >> 4 & 0xF] << 0; #endif - return zig_wrap_u8(full_res >> (8 - bits), bits); + return zig_u8_truncate_u8(full_res >> (8 - bits), bits); } -static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits); +static inline int8_t zig_bitReverse_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_bitReverse_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_bitReverse_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bitreverse16) - full_res = __builtin_bitreverse16(val); + full_res = __builtin_bitreverse16(arg); #else - full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits); +static inline int16_t zig_bitReverse_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_bitReverse_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint24_t zig_bit_reverse_u24(uint24_t val, uint8_t bits) { +static inline uint24_t zig_bitReverse_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bitreverse24) - full_res = __builtin_bitreverse24(val); + full_res = __builtin_bitreverse24(arg); #else - full_res = (uint24_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_bit_reverse_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_bitReverse_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int24_t zig_bit_reverse_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_bit_reverse_u24((uint24_t)val, bits), bits); +static inline int24_t zig_bitReverse_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_bitReverse_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bitreverse32) - full_res = __builtin_bitreverse32(val); + full_res = __builtin_bitreverse32(arg); #else - full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits); +static inline int32_t zig_bitReverse_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_bitReverse_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_bit_reverse_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bitreverse48) - full_res = __builtin_bitreverse48(val); + full_res = __builtin_bitreverse48(arg); #else - full_res = (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u32(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_bit_reverse_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_bit_reverse_u48((uint48_t)val, bits), bits); +static inline int32_t zig_bitReverse_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_bitReverse_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_bitReverse_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bitreverse64) - full_res = __builtin_bitreverse64(val); + full_res = __builtin_bitreverse64(arg); #else - full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits); +static inline int64_t zig_bitReverse_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_bitReverse_u64((uint64_t)arg, bits), bits); } -#define zig_builtin_popcount_common(w) \ - static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w((uint##w##_t)val, bits); \ +#define zig_builtin_popCount_common(w) \ + static inline uint8_t zig_popCount_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w((uint##w##_t)arg, bits); \ } -#if zig_has_builtin(popcount) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#if zig_has_builtin(popCount) || defined(zig_gcc) || defined(zig_tinyc) +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - return zig_builtin##w(popcount, val); \ + return zig_builtin##w(popcount, arg); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #else -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \ + uint##w##_t temp = arg - ((arg >> 1) & (UINT##w##_MAX / 3)); \ temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \ temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \ return temp * (UINT##w##_MAX / 255) >> (UINT8_C(w) - UINT8_C(8)); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #endif -zig_builtin_popcount(8) -zig_builtin_popcount(16) +zig_builtin_popCount(8) +zig_builtin_popCount(16) +zig_builtin_popCount(32) +zig_builtin_popCount(64) #if defined(zig_ez80) -zig_builtin_popcount(24) +zig_builtin_popCount(24) +zig_builtin_popCount(48) #endif -zig_builtin_popcount(32) -#if defined(zig_ez80) -zig_builtin_popcount(48) -#endif -zig_builtin_popcount(64) #define zig_builtin_ctz_common(w) \ - static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_ctz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(ctz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(ctz, val); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(ctz, arg); \ } \ \ zig_builtin_ctz_common(w) #else #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w(zig_not_u##w(arg, bits) & zig_subw_u##w(arg, 1, bits), bits); \ } \ \ zig_builtin_ctz_common(w) #endif zig_builtin_ctz(8) zig_builtin_ctz(16) -#if defined(zig_ez80) -zig_builtin_ctz(24) -#endif zig_builtin_ctz(32) -#if defined(zig_ez80) -zig_builtin_ctz(48) -#endif zig_builtin_ctz(64) +#if defined(zig_ez80) +zig_builtin_ctz(24) +zig_builtin_ctz(48) +#endif #define zig_builtin_clz_common(w) \ - static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_clz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_clz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_clz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(clz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(clz, arg) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ } \ \ zig_builtin_clz_common(w) #else #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w(zig_bitReverse_u##w(arg, bits), bits); \ } \ \ zig_builtin_clz_common(w) #endif zig_builtin_clz(8) zig_builtin_clz(16) -#if defined(zig_ez80) -zig_builtin_clz(24) -#endif zig_builtin_clz(32) -#if defined(zig_ez80) -zig_builtin_clz(48) -#endif zig_builtin_clz(64) +#if defined(zig_ez80) +zig_builtin_clz(24) +zig_builtin_clz(48) +#endif /* ======================== 128-bit Integer Support ========================= */ @@ -1816,16 +1980,14 @@ zig_builtin_clz(64) typedef unsigned __int128 zig_u128; typedef signed __int128 zig_i128; -#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) -#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#define zig_hi_u128(val) ((uint64_t)((val) >> 64)) -#define zig_lo_u128(val) ((uint64_t)((val) >> 0)) -#define zig_hi_i128(val) (( int64_t)((val) >> 64)) -#define zig_lo_i128(val) ((uint64_t)((val) >> 0)) -#define zig_bitCast_u128(val) ((zig_u128)(val)) -#define zig_bitCast_i128(val) ((zig_i128)(val)) +#define zig_init_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) +#define zig_init_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) +#define zig_make_u128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) zig_init_i128(hi, lo) +#define zig_hi_u128(arg) ((uint64_t)((arg) >> 64)) +#define zig_lo_u128(arg) ((uint64_t)((arg) >> 0)) +#define zig_hi_i128(arg) (( int64_t)((arg) >> 64)) +#define zig_lo_i128(arg) ((uint64_t)((arg) >> 0)) #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs > rhs) - (lhs < rhs); \ @@ -1835,32 +1997,49 @@ typedef signed __int128 zig_i128; return lhs operator rhs; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + return lhs >> rhs; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + // This works around a GCC miscompilation, but it has the side benefit of + // emitting better code. It is behind the `#if` because it depends on + // arithmetic right shift, which is implementation-defined in C, but should + // be guaranteed on any GCC-compatible compiler. +#if defined(zig_gnuc) + return lhs >> rhs; +#else + zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); + return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; +#endif +} + #else /* zig_has_int128 */ #if zig_little_endian -typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; -typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; uint64_t hi; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; int64_t hi; } zig_i128; #else -typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128; -typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t hi; uint64_t lo; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) int64_t hi; uint64_t lo; } zig_i128; #endif -#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) -#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) - -#if defined(zig_msvc) /* MSVC doesn't allow struct literals in constant expressions */ -#define zig_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#define zig_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#else /* But non-MSVC doesn't like the unprotected commas */ -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#endif -#define zig_hi_u128(val) ((val).hi) -#define zig_lo_u128(val) ((val).lo) -#define zig_hi_i128(val) ((val).hi) -#define zig_lo_i128(val) ((val).lo) -#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo) -#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo) +#define zig_init_u128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_init_i128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_make_u128(hi, lo) (zig_u128)zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) (zig_i128)zig_init_i128(hi, lo) +#define zig_hi_u128(arg) (arg).hi +#define zig_lo_u128(arg) (arg).lo +#define zig_hi_i128(arg) (arg).hi +#define zig_lo_i128(arg) (arg).lo #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs.hi == rhs.hi) \ @@ -1872,6 +2051,30 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; + return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; + return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; +} + #endif /* zig_has_int128 */ #define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64) @@ -1891,42 +2094,177 @@ zig_bit_int128(i128, or, |) zig_bit_int128(u128, xor, ^) zig_bit_int128(i128, xor, ^) -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs); +static inline uint8_t zig_u8_intCast_u128(zig_u128 arg) { + return (uint8_t)zig_lo_u128(arg); +} +static inline uint8_t zig_u8_intCast_i128(zig_i128 arg) { + return (uint8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_i128(zig_i128 arg) { + return (int8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_u128(zig_u128 arg) { + return (int8_t)zig_lo_u128(arg); +} -#if zig_has_int128 +static inline uint16_t zig_u16_intCast_u128(zig_u128 arg) { + return (uint16_t)zig_lo_u128(arg); +} +static inline uint16_t zig_u16_intCast_i128(zig_i128 arg) { + return (uint16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_i128(zig_i128 arg) { + return (int16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_u128(zig_u128 arg) { + return (int16_t)zig_lo_u128(arg); +} -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return val ^ zig_maxInt_u(128, bits); +static inline uint32_t zig_u32_intCast_u128(zig_u128 arg) { + return (uint32_t)zig_lo_u128(arg); +} +static inline uint32_t zig_u32_intCast_i128(zig_i128 arg) { + return (uint32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_i128(zig_i128 arg) { + return (int32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_u128(zig_u128 arg) { + return (int32_t)zig_lo_u128(arg); } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - (void)bits; - return ~val; +static inline uint64_t zig_u64_intCast_u128(zig_u128 arg) { + return zig_lo_u128(arg); +} +static inline uint64_t zig_u64_intCast_i128(zig_i128 arg) { + return zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_i128(zig_i128 arg) { + return (int64_t)zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_u128(zig_u128 arg) { + return (int64_t)zig_lo_u128(arg); +} + +static inline zig_u128 zig_u128_intCast_u8(uint8_t arg) { + return zig_make_u128(UINT8_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i8(int8_t arg) { + return zig_make_u128(UINT8_C(0), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_i8(int8_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_u8(uint8_t arg) { + return zig_make_i128(INT8_C(0), arg); } -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u16(uint16_t arg) { + return zig_make_u128(UINT16_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i16(int16_t arg) { + return zig_make_u128(UINT16_C(0), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_i16(int16_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_u16(uint16_t arg) { + return zig_make_i128(INT16_C(0), arg); } -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - return lhs << rhs; +static inline zig_u128 zig_u128_intCast_u32(uint32_t arg) { + return zig_make_u128(UINT32_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i32(int32_t arg) { + return zig_make_u128(UINT32_C(0), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_i32(int32_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_u32(uint32_t arg) { + return zig_make_i128(INT32_C(0), arg); } -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - // This works around a GCC miscompilation, but it has the side benefit of - // emitting better code. It is behind the `#if` because it depends on - // arithmetic right shift, which is implementation-defined in C, but should - // be guaranteed on any GCC-compatible compiler. -#if defined(zig_gnuc) - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u64(uint64_t arg) { + return zig_make_u128(UINT64_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i64(int64_t arg) { + return zig_make_u128(UINT64_C(0), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_i64(int64_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_u64(uint64_t arg) { + return zig_make_i128(INT64_C(0), arg); +} + +static inline zig_u128 zig_u128_intCast_u128(zig_u128 arg) { + return arg; +} +static inline zig_u128 zig_u128_intCast_i128(zig_i128 arg) { +#if zig_has_int128 + return (zig_u128)arg; +#else + return zig_make_u128(zig_u64_bitCast_i64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); +#endif +} +static inline zig_i128 zig_i128_intCast_i128(zig_i128 arg) { + return arg; +} +static inline zig_i128 zig_i128_intCast_u128(zig_u128 arg) { +#if zig_has_int128 + return (zig_i128)arg; #else - zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; + return zig_make_i128(zig_i64_bitCast_u64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); #endif } -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - return lhs << rhs; +#define zig_int128_cast_builtins(w) \ + static inline uint##w##_t zig_u##w##_truncate_u128(zig_u128 arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w((uint##w##_t)zig_lo_u128(arg), bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_truncate_i128(zig_i128 arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w((int##w##_t)zig_lo_i128(arg), bits); \ + } +zig_int128_cast_builtins(8) +zig_int128_cast_builtins(16) +zig_int128_cast_builtins(32) +zig_int128_cast_builtins(64) + +static inline zig_u128 zig_u128_truncate_u128(zig_u128 arg, uint8_t bits) { + return zig_and_u128(arg, zig_maxInt_u(128, bits)); +} +static inline zig_i128 zig_i128_truncate_i128(zig_i128 arg, uint8_t bits) { + if (bits > UINT8_C(64)) return zig_make_i128(zig_i64_truncate_i64(zig_hi_i128(arg), bits - UINT8_C(64)), zig_lo_i128(arg)); + int64_t lo = zig_i64_truncate_i128(arg, bits); + return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); +} + +static inline zig_u128 zig_u128_bitCast_u128(zig_u128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_u128 zig_u128_bitCast_i128(zig_i128 arg, uint8_t bits) { + return zig_u128_truncate_u128(zig_u128_intCast_i128(arg), bits); +} +static inline zig_i128 zig_i128_bitCast_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_i128 zig_i128_bitCast_u128(zig_u128 arg, uint8_t bits) { + return zig_i128_truncate_i128(zig_i128_intCast_u128(arg), bits); +} + +#if zig_has_int128 + +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + return arg ^ zig_maxInt_u(128, bits); +} + +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return ~arg; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -1953,11 +2291,11 @@ static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { return lhs * rhs; } -static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { return lhs / rhs; } -static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { return lhs / rhs; } @@ -1971,36 +2309,14 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { #else /* zig_has_int128 */ -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return (zig_u128){ .hi = UINT64_C(0), .lo = zig_not_u64(arg.lo, bits) }; + return (zig_u128){ .hi = zig_not_u64(arg.hi, bits - UINT8_C(64)), .lo = zig_not_u64(arg.lo, UINT8_C(64)) }; } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; - return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; - return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return (zig_i128){ .hi = ~arg.hi, .lo = ~arg.lo }; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -2027,59 +2343,59 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { return res; } -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); return __multi3(lhs, rhs); } static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs))); + return zig_u128_bitCast_i128(zig_mul_i128(zig_i128_bitCast_u128(lhs, UINT8_C(128)), zig_i128_bitCast_u128(rhs, UINT8_C(128))), UINT8_C(128)); } -zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); return __udivti3(lhs, rhs); } -zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); return __divti3(lhs, rhs); } -zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); return __umodti3(lhs, rhs); } -zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); return __modti3(lhs, rhs); } #endif /* zig_has_int128 */ -#define zig_div_floor_u128 zig_div_trunc_u128 +#define zig_divFloor_u128 zig_divTrunc_u128 -static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divFloor_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); } -static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divCeil_u128(zig_u128 lhs, zig_u128 rhs) { zig_u128 rem = zig_rem_u128(lhs, rhs); uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) ? UINT64_C(1) : UINT64_C(0); - return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); + return zig_add_u128(zig_divTrunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); } -static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divCeil_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); } #define zig_mod_u128 zig_rem_u128 @@ -2107,51 +2423,41 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs; } -static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) { - return zig_and_u128(val, zig_maxInt_u(128, bits)); -} - -static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) { - if (bits > UINT8_C(64)) return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val)); - int64_t lo = zig_wrap_i64((int64_t)zig_lo_i128(val), bits); - return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); -} - static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_shl_u128(lhs, rhs), bits); } static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_shl_u128(zig_u128_bitCast_i128(lhs, bits), rhs), bits), bits); } static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_add_u128(lhs, rhs), bits); } static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_add_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_sub_u128(lhs, rhs), bits); } static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_sub_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_mul_u128(lhs, rhs), bits); } static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_mul_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } -static inline zig_u128 zig_abs_i128(zig_i128 val) { - zig_i128 tmp = zig_shr_i128(val, 127); - return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp)); +static inline zig_u128 zig_abs_i128(zig_i128 arg) { + zig_u128 tmp = zig_u128_bitCast_i128(zig_shr_i128(arg, 127), UINT8_C(128)); + return zig_sub_u128(zig_xor_u128(zig_u128_bitCast_i128(arg, UINT8_C(128)), tmp), tmp); } #if zig_has_int128 @@ -2160,7 +2466,7 @@ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(add_overflow) zig_u128 full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_addw_u128(lhs, rhs, bits); @@ -2176,7 +2482,7 @@ static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs + (zig_u128)rhs); bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2184,7 +2490,7 @@ static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(sub_overflow) zig_u128 full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_subw_u128(lhs, rhs, bits); @@ -2200,7 +2506,7 @@ static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs - (zig_u128)rhs); bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2208,7 +2514,7 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(mul_overflow) zig_u128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_mulw_u128(lhs, rhs, bits); @@ -2216,8 +2522,8 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #endif } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); #if zig_has_builtin(mul_overflow) zig_i128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -2226,50 +2532,78 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } #else /* zig_has_int128 */ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_addo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_addo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_subo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_subo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { *res = zig_mulw_u128(lhs, rhs, bits); - return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) && - zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); + return zig_cmp_u128(rhs, zig_make_u128(0, 0)) != INT32_C(0) && + zig_cmp_u128(lhs, zig_divTrunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); int overflow_int; zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0 || zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) || zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0); - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow; } @@ -2282,28 +2616,54 @@ static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8 static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) { *res = zig_shlw_i128(lhs, rhs, bits); - zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1))); + zig_i128 mask = zig_i128_bitCast_u128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)), bits); return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) && zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0); } -static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { +#define zig_int128_shls_builtins(rw) \ + static inline zig_u128 zig_shls_u128_u##rw(zig_u128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_u128 res; \ + if (rhs < bits && !zig_shlo_u128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_u128(lhs, zig_make_u128(UINT64_C(0), UINT64_C(0)))) { \ + case 0: return zig_minInt_u(128, bits); \ + case 1: return zig_maxInt_u(128, bits); \ + default: zig_unreachable(); \ + } \ + } \ +\ + static inline zig_i128 zig_shls_i128_u##rw(zig_i128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_i128 res; \ + if (rhs < bits && !zig_shlo_i128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_i128(lhs, zig_make_i128(INT64_C(0), UINT64_C(0)))) { \ + case -1: return zig_minInt_i(128, bits); \ + case 0: return zig_make_i128(INT64_C(0), UINT64_C(0)); \ + case 1: return zig_maxInt_i(128, bits); \ + default: zig_unreachable(); \ + } \ + } +zig_int128_shls_builtins(8) +zig_int128_shls_builtins(16) +zig_int128_shls_builtins(32) +zig_int128_shls_builtins(64) + +static inline zig_u128 zig_shls_u128_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { zig_u128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_u128(lhs, zig_make_u128(0, 0))) { - case 0: return zig_make_u128(0, 0); - case 1: return zig_maxInt_u(128, bits); + case INT32_C(0): return zig_make_u128(0, 0); + case INT32_C(1): return zig_maxInt_u(128, bits); default: zig_unreachable(); } } -static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { +static inline zig_i128 zig_shls_i128_u128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { zig_i128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_i128(lhs, zig_make_i128(0, 0))) { - case -1: return zig_minInt_i(128, bits); - case 0: return zig_make_i128(0, 0); - case 1: return zig_maxInt_i(128, bits); + case -INT32_C(1): return zig_minInt_i(128, bits); + case INT32_C(0): return zig_make_i128(0, 0); + case INT32_C(1): return zig_maxInt_i(128, bits); default: zig_unreachable(); } } @@ -2341,57 +2701,60 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); } -static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) { - if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits); - if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64)); - return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64)); +static inline uint8_t zig_clz_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(arg), bits); + if (zig_hi_u128(arg) != 0) return zig_clz_u64(zig_hi_u128(arg), bits - UINT8_C(64)); + return zig_clz_u64(zig_lo_u128(arg), UINT8_C(64)) + (bits - UINT8_C(64)); } -static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) { - return zig_clz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_clz_i128(zig_i128 arg, uint8_t bits) { + return zig_clz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) { - if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64)); - return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64); +static inline uint8_t zig_ctz_u128(zig_u128 arg, uint8_t bits) { + if (zig_lo_u128(arg) != 0) return zig_ctz_u64(zig_lo_u128(arg), UINT8_C(64)); + return zig_ctz_u64(zig_hi_u128(arg), bits - UINT8_C(64)) + UINT8_C(64); } -static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) { - return zig_ctz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_ctz_i128(zig_i128 arg, uint8_t bits) { + return zig_ctz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) { - return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) + - zig_popcount_u64(zig_lo_u128(val), UINT8_C(64)); +static inline uint8_t zig_popCount_u128(zig_u128 arg, uint8_t bits) { + return (bits > UINT8_C(64) ? zig_popCount_u64(zig_hi_u128(arg), bits - UINT8_C(64)) : UINT8_C(0)) + + zig_popCount_u64(zig_lo_u128(arg), UINT8_C(64)); } -static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) { - return zig_popcount_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_popCount_i128(zig_i128 arg, uint8_t bits) { + return zig_popCount_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) { +static inline zig_u128 zig_byteSwap_u128(zig_u128 arg, uint8_t bits) { zig_u128 full_res; #if zig_has_builtin(bswap128) - full_res = __builtin_bswap128(val); + full_res = __builtin_bswap128(arg); #else - full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)), - zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64))); + full_res = zig_make_u128( + zig_byteSwap_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_byteSwap_u64(zig_hi_u128(arg), UINT8_C(64)) + ); #endif return zig_shr_u128(full_res, UINT8_C(128) - bits); } -static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_byteSwap_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_byteSwap_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } -static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) { - return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)), - zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))), - UINT8_C(128) - bits); +static inline zig_u128 zig_bitReverse_u128(zig_u128 arg, uint8_t bits) { + return zig_shr_u128(zig_make_u128( + zig_bitReverse_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_bitReverse_u64(zig_hi_u128(arg), UINT8_C(64)) + ), UINT8_C(128) - bits); } -static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_bitReverse_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_bitReverse_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } #if zig_has_int128 @@ -2411,12 +2774,378 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { /* ========================== Big Integer Support =========================== */ static inline uint16_t zig_int_bytes(uint16_t bits) { - uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; + uint16_t bytes = (bits - UINT16_C(1)) / CHAR_BIT + UINT16_C(1); uint16_t alignment = ZIG_TARGET_MAX_INT_ALIGNMENT; + while (alignment / 2 >= bytes) alignment /= 2; return (bytes + alignment - 1) / alignment * alignment; } +static inline void zig_minInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_minInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_minInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_minInt_u8, size - byte_offset); +#endif +} + +static inline void zig_maxInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_maxInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_maxInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_maxInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_maxInt_u8, size - byte_offset); +#endif +} + +static inline int8_t zig_signFill_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + + if (!is_signed) return INT8_C(0); +#if zig_little_endian + byte_offset = zig_int_bytes(bits) - 1; +#endif + return zig_shr_i8(zig_i8_bitCast_u8(arg_bytes[byte_offset], UINT8_C(8)), UINT8_C(7)); +} + +static inline void zig_big_intCast_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + uint16_t arg_size = zig_int_bytes(arg_bits); + uint16_t copy_size = zig_min_u16(res_size, arg_size); + uint8_t sign_fill = zig_u8_bitCast_i8(zig_signFill_big(arg, arg_is_signed, arg_bits), UINT8_C(8)); + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], copy_size); + memset(&res_bytes[copy_size], sign_fill, res_size - copy_size); +#else + memset(&res_bytes[0], sign_fill, res_size - copy_size); + memcpy(&res_bytes[res_size - copy_size], &arg_bytes[arg_size - copy_size], copy_size); +#endif +} + +static inline void zig_big_truncate_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + + if (res_is_signed != arg_is_signed) zig_unreachable(); + if (res_bits > arg_bits) zig_unreachable(); + + if (res_is_signed) { + uint16_t arg_byte_offset = UINT16_C(0); + +#if zig_big_endian + arg_byte_offset = zig_int_bytes(arg_bits) - res_size; +#endif + + memcpy(&res_bytes[0], &arg_bytes[arg_byte_offset], res_size); + } else { + uint16_t res_byte_offset = zig_shr_u16(res_bits - UINT16_C(1), UINT8_C(3)); + uint16_t arg_byte_offset = res_byte_offset; + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], res_byte_offset); +#else + res_byte_offset = res_size - UINT16_C(1) - res_byte_offset; + arg_byte_offset = zig_int_bytes(arg_bits) - UINT16_C(1) - arg_byte_offset; + + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + + res_bytes[res_byte_offset] = zig_u8_truncate_u8( + arg_bytes[arg_byte_offset], + zig_u8_truncate_u8(res_bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1) + ); + res_byte_offset += UINT16_C(1); + arg_byte_offset += UINT16_C(1); + +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, res_size - res_byte_offset); +#else + memcpy(&res_bytes[res_byte_offset], &arg_bytes[arg_byte_offset], res_size - res_byte_offset); +#endif + } +} + +#define zig_big_casts(is, s, w, IntType) \ + static inline IntType zig_##s##w##_intCast_big(const void *arg, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_intCast_big(&res, arg, is, w, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_intCast_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_intCast_big(res, &arg, res_is_signed, res_bits, is, w); \ + } \ +\ + static inline IntType zig_##s##w##_truncate_big(const void *arg, uint8_t res_bits, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_truncate_big(&res, arg, is, res_bits, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_truncate_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_truncate_big(res, &arg, res_is_signed, res_bits, is, w); \ + } +zig_big_casts(false, u, 8, uint8_t) +zig_big_casts(true , i, 8, int8_t) +zig_big_casts(false, u, 16, uint16_t) +zig_big_casts(true , i, 16, int16_t) +zig_big_casts(false, u, 32, uint32_t) +zig_big_casts(true , i, 32, int32_t) +zig_big_casts(false, u, 64, uint64_t) +zig_big_casts(true , i, 64, int64_t) +zig_big_casts(false, u, 128, zig_u128) +zig_big_casts(true , i, 128, zig_i128) + +static inline void zig_big_bitCast_big(void *res, const void *arg, bool res_is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + +#if zig_big_endian + byte_offset = size - UINT16_C(1) - byte_offset; +#endif + + if (res_is_signed) { + int8_t signed_sign_byte = zig_i8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_u8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memcpy(&res_bytes[byte_offset], &arg_bytes[byte_offset], size - byte_offset); +#endif +} + +static inline int32_t zig_cmp_big_u8(const void *lhs, uint8_t rhs, bool is_signed, uint16_t bits) { + const uint8_t *lhs_bytes = lhs; + uint16_t byte_offset = 0; + bool do_signed = is_signed; + uint16_t remaining_bytes = zig_int_bytes(bits); + +#if zig_little_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 128 / CHAR_BIT ? rhs : UINT8_C(0); + int32_t limb_cmp; + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (do_signed) { + zig_i128 lhs_limb; + zig_i128 rhs_limb = zig_i128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); + do_signed = false; + } else { + zig_u128 lhs_limb; + zig_u128 rhs_limb = zig_u128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); + } + + if (limb_cmp != 0) return limb_cmp; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 64 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (do_signed) { + int64_t lhs_limb; + int64_t rhs_limb = zig_i64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint64_t lhs_limb; + uint64_t rhs_limb = zig_u64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 32 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (do_signed) { + int32_t lhs_limb; + int32_t rhs_limb = zig_i32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint32_t lhs_limb; + uint32_t rhs_limb = zig_u32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (do_signed) { + int16_t lhs_limb; + int16_t rhs_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint16_t lhs_limb; + uint16_t rhs_limb = zig_u16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (do_signed) { + int8_t lhs_limb; + int16_t lhs_cmp_limb; + int16_t rhs_cmp_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + lhs_cmp_limb = zig_i16_intCast_i8(lhs_limb); + if (lhs_cmp_limb != rhs_cmp_limb) return (lhs_cmp_limb > rhs_cmp_limb) - (lhs_cmp_limb < rhs_cmp_limb); + do_signed = false; + } else { + uint8_t lhs_limb; + uint8_t rhs_limb = rhs_byte; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return 0; +} + static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; @@ -2579,6 +3308,168 @@ static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_sign return 0; } +static inline void zig_not_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (remaining_bytes != 128 / CHAR_BIT || is_signed) { + zig_i128 res_limb; + zig_i128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (remaining_bytes != 64 / CHAR_BIT || is_signed) { + int64_t res_limb; + int64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (remaining_bytes != 32 / CHAR_BIT || is_signed) { + int32_t res_limb; + int32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (remaining_bytes != 16 / CHAR_BIT || is_signed) { + int16_t res_limb; + int16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (remaining_bytes != 8 / CHAR_BIT || is_signed) { + int8_t res_limb; + int8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; @@ -2816,13 +3707,415 @@ static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool } } +static inline void zig_increment_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_decrement_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_abs_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + if (zig_signFill_big(arg, is_signed, bits) >= INT8_C(0)) { + memcpy(res, arg, remaining_bytes); + return; + } + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool overflow = true; + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u128(&res_limb, zig_not_u128(arg_limb, UINT8_C(128)), zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u64(&res_limb, zig_not_u64(arg_limb, UINT8_C(64)), overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u32(&res_limb, zig_not_u32(arg_limb, UINT8_C(32)), overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u16(&res_limb, zig_not_u16(arg_limb, UINT8_C(16)), overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u8(&res_limb, zig_not_u8(arg_limb, UINT8_C(8)), overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_min_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) < INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + +static inline void zig_max_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) >= INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3038,7 +4331,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3248,323 +4541,755 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo return overflow; } +static inline void zig_add_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_addo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_addw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_addo_big(res, lhs, rhs, is_signed, bits); } +static inline void zig_adds_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits); + + if (!zig_addo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } +} + +static inline void zig_sub_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_subo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_subo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __udivei4(res, lhs, rhs, bits); - return; - } +static inline void zig_subs_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = is_signed ? zig_signFill_big(lhs, is_signed, bits) : -INT8_C(1); - zig_trap(); + if (!zig_subo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } } -static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_div_trunc_big(res, lhs, rhs, is_signed, bits); - return; +static inline bool zig_mulo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + const uint8_t *rhs_bytes = rhs; + uint16_t size = zig_int_bytes(bits); + uint16_t sign_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint8_t rhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(rhs, is_signed, bits), UINT8_C(8)); + uint16_t lhs_byte_offset = sign_byte_offset; + uint16_t lhs_end_byte_offset = UINT16_C(0); + bool overflow = false; + +#if zig_big_endian + lhs_byte_offset = size - lhs_byte_offset; + lhs_end_byte_offset = size - lhs_end_byte_offset; +#endif + + while (lhs_byte_offset != lhs_end_byte_offset) { + uint16_t rhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint16_t res_byte_offset; + uint16_t lhs_byte; + uint8_t res_byte = UINT8_C(0); + uint16_t mul_res = UINT16_C(0); + uint8_t carry = UINT8_C(0); + +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#else + rhs_byte_offset = size - rhs_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + + lhs_byte = zig_u16_intCast_u8(lhs_bytes[lhs_byte_offset]) ^ lhs_sign_fill; + +#if zig_big_endian + lhs_byte_offset += UINT16_C(1); +#endif + + res_byte_offset = lhs_byte_offset; + + while (res_byte_offset != end_byte_offset) { + bool res_byte_initialized = res_byte_offset != lhs_byte_offset; + +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); + res_byte_offset -= UINT16_C(1); +#endif + + if (res_byte_initialized) res_byte = res_bytes[res_byte_offset]; + carry = zig_addo_u8(&res_byte, res_byte, carry, UINT8_C(8)); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_intCast_u16( + zig_shr_u16(mul_res, UINT8_C(8)) + ), UINT8_C(8)); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_bytes[res_byte_offset], res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); + res_byte_offset += UINT16_C(1); +#endif + } + + while (rhs_byte_offset != end_byte_offset) { +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); +#endif + + carry = zig_addo_u8( + &res_byte, + zig_u8_intCast_u16(zig_shr_u16(mul_res, UINT8_C(8))), + carry, + UINT8_C(8) + ); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + overflow |= res_byte != UINT8_C(0); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); +#endif + } + + overflow |= zig_shr_u16(mul_res, UINT8_C(8)) != UINT16_C(0); + overflow |= carry != UINT8_C(0); } - zig_trap(); +#if zig_little_endian + sign_byte_offset -= UINT64_C(1); +#else + sign_byte_offset = size - sign_byte_offset; +#endif + + if (lhs_sign_fill != rhs_sign_fill) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(0); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, UINT8_C(0), carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, res_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8( + &res_bytes[byte_offset], + res_byte, + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, INT8_C(0), signed_res_byte, UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (lhs_sign_fill != UINT8_C(0)) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(1); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, res_bytes[byte_offset], carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, lhs_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8(&res_bytes[byte_offset], res_byte, rhs_bytes[byte_offset], UINT8_C(8)); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + lhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + rhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (is_signed) { + int8_t signed_res_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + + overflow |= signed_res_byte < INT8_C(0); + } + + { + uint8_t truncate_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t fill_byte = UINT8_C(0); + + if (is_signed) { + int8_t sign_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + int8_t truncated = zig_i8_truncate_i8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + } else { + uint8_t sign_byte = res_bytes[sign_byte_offset]; + uint8_t truncated = zig_u8_truncate_u8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = truncated; + } + +#if zig_little_endian + sign_byte_offset += UINT16_C(1); + memset(&res_bytes[sign_byte_offset], fill_byte, size - sign_byte_offset); +#else + memset(&res_bytes[0], fill_byte, sign_byte_offset); +#endif + } + + return overflow; +} + +static inline void zig_mul_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_mulo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow } -static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - zig_trap(); +static inline void zig_mulw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + (void)zig_mulo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __umodei4(res, lhs, rhs, bits); - return; +static inline void zig_muls_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits) ^ zig_signFill_big(rhs, is_signed, bits); + + if (!zig_mulo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); } +} + +static inline void zig_divTrunc_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __divei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __divei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __udivei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __udivei5(res, lhs, rhs, temp, bits); + } +} - zig_trap(); +static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __modei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __modei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __umodei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __umodei5(res, lhs, rhs, temp, bits); + } } -static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_rem_big(res, lhs, rhs, is_signed, bits); - return; +static inline void zig_divFloor_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool decrement = false; + + if (is_signed) { + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + decrement = zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32)); } + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (decrement) zig_decrement_big(res, is_signed, bits); +} - zig_trap(); +static inline void zig_divCeil_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool increment = false; + + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + increment = zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ) > INT32_C(0); + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (increment) zig_increment_big(res, is_signed, bits); } -static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t skip_bits = remaining_bytes * 8 - bits; - uint16_t total_lz = 0; - uint16_t limb_lz; - (void)is_signed; +static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool fixup = false; -#if zig_little_endian - byte_offset = remaining_bytes; + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + if (is_signed && zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32))) zig_add_big(res, res, rhs, is_signed, bits); +} + +static inline void zig_shr_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t lhs_byte_offset = zig_shr_u16(rhs, UINT8_C(3)); + uint16_t end_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_prev_byte; + uint8_t byte_shift = zig_u8_truncate_u16(rhs, UINT8_C(3)); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + lhs_byte_offset = size - lhs_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - while (remaining_bytes >= 128 / CHAR_BIT) { + { +#if zig_big_endian + lhs_byte_offset -= UINT16_C(1); +#endif + + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; + #if zig_little_endian - byte_offset -= 128 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); +#endif + } + + while (lhs_byte_offset != end_byte_offset) { +#if zig_big_endian + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - zig_u128 val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u128(val_limb, 128 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_prev_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 128 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; + { + uint8_t lhs_sign_fill = UINT8_C(0); + +#if zig_big_endian + res_byte_offset -= UINT16_C(1); #endif - { - uint64_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(lhs_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u64(val_limb, 64 - skip_bits); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + lhs_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(lhs_prev_byte, byte_shift); } - total_lz += limb_lz; - if (limb_lz < 64 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], lhs_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], lhs_sign_fill, res_byte_offset); #endif } +} + +static inline bool zig_shlo_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t lhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = res_byte_offset - UINT16_C(1) - zig_shr_u16(rhs, UINT8_C(3)); + uint8_t lhs_prev_byte = lhs_sign_fill; + uint8_t byte_shift = UINT8_C(8) - zig_u8_truncate_u16(rhs, UINT8_C(3)); + bool overflow = false; - while (remaining_bytes >= 32 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 32 / CHAR_BIT; + lhs_byte_offset = size - lhs_byte_offset; +#else + res_byte_offset = size - res_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u32(val_limb, 32 - skip_bits); - } + while (lhs_byte_offset != end_byte_offset) { +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#endif - total_lz += limb_lz; - if (limb_lz < 32 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 32 / CHAR_BIT; + overflow |= lhs_prev_byte != lhs_sign_fill; + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; #if zig_big_endian - byte_offset += 32 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 16 / CHAR_BIT; + end_byte_offset = UINT16_C(0); +#else + end_byte_offset = size; +#endif + + { + bool lhs_more_bytes = lhs_byte_offset != end_byte_offset; + +#if zig_little_endian + if (lhs_more_bytes) lhs_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t lhs_byte = UINT8_C(0); + + if (lhs_more_bytes) lhs_byte = lhs_bytes[lhs_byte_offset]; + + if (is_signed) { + int16_t shifted = zig_shr_i16(zig_or_i16( + zig_shl_i16(zig_i16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_i16_intCast_u8(lhs_byte) + ), byte_shift); + int8_t truncated = zig_i8_truncate_i16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + uint8_t fill = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + + overflow |= zig_i16_intCast_i8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif + res_bytes[res_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + } else { + uint16_t shifted = zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift); + uint8_t truncated = zig_u8_truncate_u16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + + overflow |= zig_u16_intCast_u8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + res_bytes[res_byte_offset] = truncated; + } - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u16(val_limb, 16 - skip_bits); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 16 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_big_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + if (lhs_more_bytes) lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + while (lhs_byte_offset != end_byte_offset) { #if zig_little_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - uint8_t val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u8(val_limb, 8 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 8 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_big_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - return total_lz; -} + { +#if zig_little_endian + res_byte_offset -= UINT16_C(1); +#endif -static inline uint16_t zig_ctz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_tz = 0; - uint16_t limb_tz; - (void)is_signed; + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + byte_shift + )); #if zig_big_endian - byte_offset = remaining_bytes; + res_byte_offset += UINT16_C(1); #endif + } - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#else + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); #endif - { - zig_u128 val_limb; + return overflow; +} - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u128(val_limb, 128); - } +static inline void zig_shl_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + if (zig_shlo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: left shift overflowed bits +} - total_tz += limb_tz; - if (limb_tz < 128) return total_tz; - remaining_bytes -= 128 / CHAR_BIT; +static inline void zig_shlw_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + (void)zig_shlo_big(res, lhs, rhs, is_signed, bits); +} -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif +#define zig_big_shls_builtin(w) \ + static inline uint##w##_t zig_shls_u##w##_big(uint##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + uint##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_u##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? zig_minInt_u(w, lhs_bits) : zig_maxInt_u(w, lhs_bits); \ + } \ +\ + static inline int##w##_t zig_shls_i##w##_big(int##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + int##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_i##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ + lhs < INT##w##_C(0) ? zig_minInt_i(w, lhs_bits) : zig_maxInt_i(w, lhs_bits); \ + } \ +\ + static inline void zig_shls_big_u##w(void *res, const void *lhs, uint##w##_t rhs, bool is_signed, uint16_t bits) { \ + const uint8_t *lhs_bytes = lhs; \ + if (rhs < bits && !zig_shlo_big(res, lhs, zig_u16_intCast_u##w(rhs), is_signed, bits)) return; \ + switch (zig_cmp_big_u8(lhs, UINT8_C(0), is_signed, bits)) { \ + case -INT32_C(1): return zig_minInt_big(res, is_signed, bits); \ + case INT32_C(0): return zig_minInt_big(res, false, bits); \ + case INT32_C(1): return zig_maxInt_big(res, is_signed, bits); \ + default: zig_unreachable(); \ + } \ } +zig_big_shls_builtin(8) +zig_big_shls_builtin(16) +zig_big_shls_builtin(32) +zig_big_shls_builtin(64) + +static inline void zig_byteSwap_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = bits / CHAR_BIT; + uint16_t end_byte_offset = UINT16_C(1); + uint16_t size = zig_int_bytes(bits); - while (remaining_bytes >= 64 / CHAR_BIT) { #if zig_big_endian - byte_offset -= 64 / CHAR_BIT; + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u64(val_limb, 64); - } + while (arg_byte_offset != end_byte_offset) { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); +#endif - total_tz += limb_tz; - if (limb_tz < 64) return total_tz; - remaining_bytes -= 64 / CHAR_BIT; + res_bytes[res_byte_offset] = arg_bytes[arg_byte_offset]; #if zig_little_endian - byte_offset += 64 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; + { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); #endif { - uint32_t val_limb; + uint8_t byte = arg_bytes[arg_byte_offset]; + uint8_t fill = is_signed + ? zig_u8_bitCast_i8(zig_shr_i8(zig_i8_bitCast_u8(byte, UINT8_C(8)), UINT8_C(7)), UINT8_C(8)) + : UINT8_C(0); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u32(val_limb, 32); + res_bytes[res_byte_offset] = byte; + +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif } + } +} - total_tz += limb_tz; - if (limb_tz < 32) return total_tz; - remaining_bytes -= 32 / CHAR_BIT; +static inline void zig_bitReverse_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t end_byte_offset = UINT16_C(0); + uint8_t arg_prev_byte; + uint8_t byte_shift = zig_u8_intCast_u16(zig_subw_u16(UINT16_C(0), bits, UINT8_C(3))); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + { #if zig_little_endian - byte_offset += 32 / CHAR_BIT; + arg_byte_offset -= UINT16_C(1); +#endif + + arg_prev_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); + +#if zig_big_endian + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { + while (arg_byte_offset != end_byte_offset) { #if zig_big_endian - byte_offset -= 16 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); +#else + arg_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t arg_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u16(val_limb, 16); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(arg_byte), UINT8_C(8)), + zig_u16_intCast_u8(arg_prev_byte) + ), byte_shift)); + arg_prev_byte = arg_byte; } - total_tz += limb_tz; - if (limb_tz < 16) return total_tz; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_little_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + { + uint8_t arg_sign_fill = UINT8_C(0); + #if zig_big_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); #endif - { - uint8_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(arg_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u8(val_limb, 8); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + arg_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(arg_prev_byte, byte_shift); } - total_tz += limb_tz; - if (limb_tz < 8) return total_tz; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_little_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], arg_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], arg_sign_fill, res_byte_offset); #endif } - - return total_tz; } -static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; +static inline uint16_t zig_popCount_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); uint16_t total_pc = 0; (void)is_signed; #if zig_big_endian - byte_offset = remaining_bytes; + byte_offset = zig_int_bytes(bits); #endif while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 128 / CHAR_BIT; #endif { - zig_u128 val_limb; + zig_u128 arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u128(val_limb, 128); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 128 / CHAR_BIT; @@ -3575,15 +5300,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 64 / CHAR_BIT; #endif { - uint64_t val_limb; + uint64_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u64(val_limb, 64); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 64 / CHAR_BIT; @@ -3594,15 +5321,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 32 / CHAR_BIT; #endif { - uint32_t val_limb; + uint32_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u32(val_limb, 32); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 32 / CHAR_BIT; @@ -3613,15 +5342,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 16 / CHAR_BIT; #endif { - uint16_t val_limb; + uint16_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u16(val_limb, 16); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 16 / CHAR_BIT; @@ -3632,15 +5363,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 8 / CHAR_BIT; #endif { - uint8_t val_limb; + uint8_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u8(val_limb, 8); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 8 / CHAR_BIT; @@ -3653,6 +5386,274 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ return total_pc; } +static inline uint16_t zig_ctz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = UINT16_C(0); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + uint16_t total_tz = UINT16_C(0); + uint16_t limb_tz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits); +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_tz; +} + +static inline uint16_t zig_clz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t remaining_bytes = byte_offset; + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool sign_limb = true; + uint16_t total_lz = UINT16_C(0); + uint16_t limb_lz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits) - remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(128) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(64) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(32) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(16) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(8) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_lz; +} + /* ========================= Floating Point Support ========================= */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ @@ -3687,29 +5688,29 @@ long double __cdecl nanl(char const* input); #define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg) #define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) #else -#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr) -#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr) -#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr) -#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr) -#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr) +#define zig_make_special_f16(sign, name, arg, repr) zig_f16_bitCast_u16 (repr) +#define zig_make_special_f32(sign, name, arg, repr) zig_f32_bitCast_u32 (repr) +#define zig_make_special_f64(sign, name, arg, repr) zig_f64_bitCast_u64 (repr) +#define zig_make_special_f80(sign, name, arg, repr) zig_f80_bitCast_u128(repr) +#define zig_make_special_f128(sign, name, arg, repr) zig_f128_bitCast_u128(repr) #endif #define zig_has_f16 1 #define zig_libc_name_f16(name) __##name##h #define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) -#if FLT_MANT_DIG == 11 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT_MANT_DIG == 11 typedef float zig_f16; #define zig_make_f16(fp, repr) fp##f -#elif DBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && DBL_MANT_DIG == 11 typedef double zig_f16; #define zig_make_f16(fp, repr) fp -#elif LDBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && LDBL_MANT_DIG == 11 typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) typedef _Float16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 -#elif defined(__SIZEOF_FP16__) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && defined(__SIZEOF_FP16__) typedef __fp16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 #else @@ -3723,11 +5724,6 @@ typedef uint16_t zig_f16; #undef zig_init_special_f16 #define zig_init_special_f16(sign, name, arg, repr) repr #endif -#if defined(zig_darwin) && defined(zig_x86) -typedef uint16_t zig_compiler_rt_f16; -#else -typedef zig_f16 zig_compiler_rt_f16; -#endif #define zig_has_f32 1 #define zig_libc_name_f32(name) name##f @@ -3736,16 +5732,16 @@ typedef zig_f16 zig_compiler_rt_f16; #else #define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 24 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT_MANT_DIG == 24 typedef float zig_f32; #define zig_make_f32(fp, repr) fp##f -#elif DBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && DBL_MANT_DIG == 24 typedef double zig_f32; #define zig_make_f32(fp, repr) fp -#elif LDBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && LDBL_MANT_DIG == 24 typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l -#elif FLT32_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT32_MANT_DIG == 24 typedef _Float32 zig_f32; #define zig_make_f32(fp, repr) fp##f32 #else @@ -3768,19 +5764,19 @@ typedef uint32_t zig_f32; #else #define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 53 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT_MANT_DIG == 53 typedef float zig_f64; #define zig_make_f64(fp, repr) fp##f -#elif DBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && DBL_MANT_DIG == 53 typedef double zig_f64; #define zig_make_f64(fp, repr) fp -#elif LDBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && LDBL_MANT_DIG == 53 typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l -#elif FLT64_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT64_MANT_DIG == 53 typedef _Float64 zig_f64; #define zig_make_f64(fp, repr) fp##f64 -#elif FLT32X_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT32X_MANT_DIG == 53 typedef _Float32x zig_f64; #define zig_make_f64(fp, repr) fp##f32x #else @@ -3798,7 +5794,14 @@ typedef uint64_t zig_f64; #define zig_has_f80 1 #define zig_libc_name_f80(name) __##name##x #define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) -#if FLT_MANT_DIG == 64 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F80_ABI +#undef zig_has_f80 +typedef struct { uint64_t mantissa; uint16_t exponent; } zig_f80; +#define zig_init_repr_f80(mantissa, exponent) { .mant##issa = mantissa, .expo##nent = exponent } +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#define zig_mantissa_repr_f80(arg) (arg).mantissa +#define zig_exponent_repr_f80(arg) (arg).exponent +#elif FLT_MANT_DIG == 64 typedef float zig_f80; #define zig_make_f80(fp, repr) fp##f #elif DBL_MANT_DIG == 64 @@ -3818,68 +5821,91 @@ typedef __float80 zig_f80; #define zig_make_f80(fp, repr) fp##l #else #undef zig_has_f80 -#define zig_has_f80 0 -#define zig_repr_f80 u128 typedef zig_u128 zig_f80; +#define zig_init_repr_f80(mantissa, exponent) zig_init_u128(exponent, mantissa) +#define zig_make_repr_f80(mantissa, exponent) zig_make_u128(exponent, mantissa) +#define zig_mantissa_repr_f80(arg) zig_lo_u128(arg) +#define zig_exponent_repr_f80(arg) (uint16_t)zig_hi_u128(arg) +#endif +#ifndef zig_has_f80 +#define zig_has_f80 0 #define zig_make_f80(fp, repr) repr +#ifndef zig_make_repr_f80 +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#endif #undef zig_make_special_f80 #define zig_make_special_f80(sign, name, arg, repr) repr #undef zig_init_special_f80 #define zig_init_special_f80(sign, name, arg, repr) repr #endif -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif - #define zig_has_f128 1 -#define zig_libc_name_f128(name) name##q +#define zig_libc_name_f128(name) name##f128 #define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) -#if !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F128_ABI +#undef zig_has_f128 +#if zig_little_endian +typedef struct { uint64_t lo, hi; } zig_f128; +#else +typedef struct { uint64_t hi, lo; } zig_f128; +#endif +#define zig_init_repr_f128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_lo_repr_f128(arg) (arg).lo +#define zig_hi_repr_f128(arg) (arg).hi +#elif FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 +#elif DBL_MANT_DIG == 113 typedef double zig_f128; #define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 +#elif LDBL_MANT_DIG == 113 typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 +#elif FLT128_MANT_DIG == 113 typedef _Float128 zig_f128; #define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 +#elif FLT64X_MANT_DIG == 113 typedef _Float64x zig_f128; #define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) +#elif defined(__SIZEOF_FLOAT128__) typedef __float128 zig_f128; #define zig_make_f128(fp, repr) fp##q #undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg) #else #undef zig_has_f128 -#define zig_has_f128 0 -#undef zig_make_special_f128 -#undef zig_init_special_f128 -#if defined(zig_darwin) || defined(zig_aarch64) -typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64; -zig_basic_operator(zig_v2u64, xor_v2u64, ^) -#define zig_repr_f128 v2u64 -typedef zig_v2u64 zig_f128; -#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi } -#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128 -#define zig_make_f128(fp, repr) zig_make_f128_##repr -#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr +#if defined(zig_x86_64) && defined(ZIG_TARGET_ABI_MSVC) +#if defined(zig_msvc) && !defined(__clang__) +#include +typedef __m128i zig_f128; +#define zig_init_repr_f128(hi, lo) { .m128i_u64 = { lo, hi } } +#define zig_lo_repr_f128(arg) (arg).m128i_u64[0] +#define zig_hi_repr_f128(arg) (arg).m128i_u64[1] +#else +typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_f128; +#define zig_init_repr_f128(hi, lo) { lo, hi } +#define zig_lo_repr_f128(arg) (arg)[0] +#define zig_hi_repr_f128(arg) (arg)[1] +#endif #else -#define zig_repr_f128 u128 typedef zig_u128 zig_f128; +#define zig_init_repr_f128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_repr_f128(hi, lo) zig_make_u128(hi, lo) +#define zig_lo_repr_f128(arg) zig_lo_u128(arg) +#define zig_hi_repr_f128(arg) zig_hi_u128(arg) +#endif +#endif +#ifndef zig_has_f128 +#define zig_has_f128 0 #define zig_make_f128(fp, repr) repr +#ifndef zig_make_repr_f128 +#define zig_make_repr_f128(hi, lo) (zig_f128)zig_init_repr_f128(hi, lo) +#endif +#undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) repr +#undef zig_init_special_f128 #define zig_init_special_f128(sign, name, arg, repr) repr #endif -#endif #if !defined(zig_msvc) && defined(ZIG_TARGET_ABI_MSVC) /* Emulate msvc abi on a gnu compiler */ @@ -3892,84 +5918,141 @@ typedef zig_f128 zig_c_longdouble; typedef long double zig_c_longdouble; #endif -#define zig_bitCast_float(Type, ReprType) \ - static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \ - zig_##Type result; \ - memcpy(&result, &repr, sizeof(result)); \ - return result; \ +#if __AVR__ +typedef signed char zig_FloatCompareResult; +#elif defined(zig_aarch64) +typedef signed int zig_FloatCompareResult; +#elif __SIZEOF_LONG__ >= __SIZEOF_POINTER__ +typedef signed long zig_FloatCompareResult; +#else +typedef signed long long zig_FloatCompareResult; +#endif + +#define zig_bitCast_float(w, iw, UnsignedReprType, SignedReprType) \ + static inline zig_f##w zig_f##w##_bitCast_u##iw(UnsignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline zig_f##w zig_f##w##_bitCast_i##iw(SignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline UnsignedReprType zig_u##iw##_bitCast_f##w(zig_f##w arg) { \ + UnsignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_u##iw##_truncate_u##iw(res, w); \ + } \ + static inline SignedReprType zig_i##iw##_bitCast_f##w(zig_f##w arg) { \ + SignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_i##iw##_truncate_i##iw(res, w); \ + } +zig_bitCast_float(16, 16, uint16_t, int16_t) +zig_bitCast_float(32, 32, uint32_t, int32_t) +zig_bitCast_float(64, 64, uint64_t, int64_t) +#if zig_has_f80 +zig_bitCast_float(80, 128, zig_u128, zig_i128) +#else +static inline zig_f80 zig_f80_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f80(zig_lo_u128(arg), (uint16_t)zig_hi_u128(arg)); +} +static inline zig_f80 zig_f80_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f80(zig_lo_i128(arg), (uint16_t)zig_hi_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f80(zig_f80 arg) { + return zig_make_u128(zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +static inline zig_i128 zig_i128_bitCast_f80(zig_f80 arg) { + return zig_make_i128((int16_t)zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +#endif +static inline zig_f80 zig_f80_bitCast_big(const void *arg) { + return zig_f80_bitCast_u128(zig_u128_truncate_big(arg, UINT8_C(80), false, UINT16_C(80))); +} +static inline void zig_big_bitCast_f80(void *res, zig_f80 arg, bool res_is_signed, uint16_t res_bits) { + if (res_is_signed) { + zig_big_truncate_i128(res, zig_i128_bitCast_f80(arg), res_is_signed, res_bits); + } else { + zig_big_truncate_u128(res, zig_u128_bitCast_f80(arg), res_is_signed, res_bits); } -zig_bitCast_float(f16, uint16_t) -zig_bitCast_float(f32, uint32_t) -zig_bitCast_float(f64, uint64_t) -zig_bitCast_float(f80, zig_u128) -zig_bitCast_float(f128, zig_u128) +} +#if zig_has_f128 +zig_bitCast_float(128, 128, zig_u128, zig_i128) +#else +static inline zig_f128 zig_f128_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f128(zig_hi_u128(arg), zig_lo_u128(arg)); +} +static inline zig_f128 zig_f128_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f128((uint64_t)zig_hi_i128(arg), zig_lo_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f128(zig_f128 arg) { + return zig_make_u128(zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +static inline zig_i128 zig_i128_bitCast_f128(zig_f128 arg) { + return zig_make_i128((int64_t)zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +#endif -#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \ - zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \ +#define zig_convert_float_00(ResType, operation, ArgType, version) \ + zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType arg); \ + return zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(arg) +#define zig_convert_float_01(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_10(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_11(ResType, operation, ArgType, version) \ + return (ResType)arg +#define zig_convert_float(res_when, ResType, operation, arg_when, ArgType, version) \ static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \ - ResType res; \ - ExternResType extern_res; \ - ExternArgType extern_arg; \ - memcpy(&extern_arg, &arg, sizeof(extern_arg)); \ - extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \ - memcpy(&res, &extern_res, sizeof(res)); \ - return extern_res; \ + zig_expand_concat(zig_expand_concat(zig_convert_float_, zig_has_##res_when), \ + zig_has_##arg_when)(ResType, operation, ArgType, version); \ } -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2) -#ifdef __ARM_EABI__ +#define zig_convert_floats(SmallType, BigType) \ + zig_convert_float(SmallType, zig_##SmallType, trunc, BigType, zig_##BigType, 2) \ + zig_convert_float(BigType, zig_##BigType, extend, SmallType, zig_##SmallType, 2) +zig_convert_floats(f16, f32) +zig_convert_floats(f16, f64) +zig_convert_floats(f16, f80) +zig_convert_floats(f16, f128) +zig_convert_floats(f32, f64) +zig_convert_floats(f32, f80) +zig_convert_floats(f32, f128) +zig_convert_floats(f64, f80) +zig_convert_floats(f64, f128) +zig_convert_floats(f80, f128) -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_d2f(zig_f64); -static inline zig_f32 zig_truncdfsf(zig_f64 arg) { return __aeabi_d2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_f2d(zig_f32); -static inline zig_f64 zig_extendsfdf(zig_f32 arg) { return __aeabi_f2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2) - -#endif /* __ARM_EABI__ */ - -#define zig_float_negate_builtin_0(w, c, sb) \ - zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb)) -#define zig_float_negate_builtin_1(w, c, sb) -arg -#define zig_float_negate_builtin(w, c, sb) \ +#define zig_float_negate_builtin_0(w, sb) \ + zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, sb)) +#define zig_float_negate_builtin_1(w, sb) -arg +#define zig_float_negate_builtin(w, sb) \ static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \ - return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \ + return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, sb); \ } -zig_float_negate_builtin(16, , UINT16_C(1) << 15 ) -zig_float_negate_builtin(32, , UINT32_C(1) << 31 ) -zig_float_negate_builtin(64, , UINT64_C(1) << 63 ) -zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0))) -zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) +zig_float_negate_builtin(16, UINT16_C(1) << 15) +zig_float_negate_builtin(32, UINT32_C(1) << 31) +zig_float_negate_builtin(64, UINT64_C(1) << 63) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_mantissa_repr_f##w(arg), zig_xor_u16(zig_exponent_repr_f##w(arg), sb)) +zig_float_negate_builtin(80, UINT16_C(1) << 15) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_xor_u64(zig_hi_repr_f##w(arg), sb), zig_lo_repr_f##w(arg)) +zig_float_negate_builtin(128, UINT64_C(1) << 63) #define zig_float_less_builtin_0(Type, operation) \ - zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \ + zig_extern zig_FloatCompareResult zig_expand_concat(zig_expand_concat(__##operation, \ zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ + return (int32_t)zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ } #define zig_float_less_builtin_1(Type, operation) \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ @@ -3994,13 +6077,52 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) return lhs operator rhs; \ } +#define zig_float_builtins(w) \ + zig_common_float_builtins(w) \ + zig_convert_float(f##w, zig_f##w, float, int128, zig_i128, ) \ + zig_convert_float(f##w, zig_f##w, floatun, int128, zig_u128, ) #define zig_common_float_builtins(w) \ - zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \ + zig_convert_float(always, int32_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, int64_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_i128, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, uint32_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(always, uint64_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_u128, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int32_t, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int64_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint32_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint64_t, ) \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatunei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \ @@ -4031,82 +6153,48 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_max_f##w, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_fma_f##w, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ \ - static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divTrunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_trunc_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divFloor_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divCeil_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ + return zig_sub_f##w(lhs, zig_mul_f##w(zig_divFloor_f##w(lhs, rhs), rhs)); \ } -zig_common_float_builtins(16) -zig_common_float_builtins(32) -zig_common_float_builtins(64) -zig_common_float_builtins(80) -zig_common_float_builtins(128) - -#define zig_float_builtins(w) \ - zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) zig_float_builtins(16) -zig_float_builtins(80) -zig_float_builtins(128) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_f2iz(zig_f32); -static inline int32_t zig_fixsfsi(zig_f32 arg) { return __aeabi_f2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_f2uiz(zig_f32); -static inline uint32_t zig_fixunssfsi(zig_f32 arg) { return __aeabi_f2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_f2ulz(zig_f32); -static inline uint64_t zig_fixunssfdi(zig_f32 arg) { return __aeabi_f2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_i2f(int32_t); -static inline zig_f32 zig_floatsisf(int32_t arg) { return __aeabi_i2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ui2f(uint32_t); -static inline zig_f32 zig_floatunsisf(uint32_t arg) { return __aeabi_ui2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ul2f(uint64_t); -static inline zig_f32 zig_floatundisf(uint64_t arg) { return __aeabi_ul2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_d2iz(zig_f64); -static inline int32_t zig_fixdfsi(zig_f64 arg) { return __aeabi_d2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_d2uiz(zig_f64); -static inline uint32_t zig_fixunsdfsi(zig_f64 arg) { return __aeabi_d2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_d2ulz(zig_f64); -static inline uint64_t zig_fixunsdfdi(zig_f64 arg) { return __aeabi_d2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_i2d(int32_t); -static inline zig_f64 zig_floatsidf(int32_t arg) { return __aeabi_i2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ui2d(uint32_t); -static inline zig_f64 zig_floatunsidf(uint32_t arg) { return __aeabi_ui2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ul2d(uint64_t); -static inline zig_f64 zig_floatundidf(uint64_t arg) { return __aeabi_ul2d(arg); } - -#else /* __ARM_EABI__ */ - zig_float_builtins(32) zig_float_builtins(64) - -#endif /* __ARM_EABI__ */ +zig_float_builtins(80) +#if defined(zig_x86_32) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_f128 arg); + return __floattitf(zig_f128_bitCast_i128(arg)); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(zig_f128 arg); + return __floatuntitf(zig_f128_bitCast_u128(arg)); +} +#elif defined(zig_x86_64) && defined(zig_windows) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_i128 arg); + return __floattitf(arg); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(uint64_t arg_lo, uint64_t arg_hi); + return __floatuntitf(zig_lo_u128(arg), zig_hi_u128(arg)); +} +#else +zig_float_builtins(128) +#endif /* ============================ Atomics Support ============================= */ @@ -4410,19 +6498,19 @@ typedef int zig_memory_order; } \ static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ (void)_InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ + } \ static inline Type zig_msvc_atomic_load_zig_memory_order_relaxed_##ZigType(Type volatile* obj) { \ return __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_acquire_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } zig_msvc_atomics( u8, uint8_t, char, 8, 8) @@ -4465,14 +6553,14 @@ zig_msvc_atomics(i64, int64_t, __int64, 64, 64) zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } \ static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##Type(zig_##Type volatile* obj) { \ zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } @@ -4502,9 +6590,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p32(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p32(void volatile* obj) { - void* val = (void*)__iso_volatile_load32(obj); + void* value = (void*)__iso_volatile_load32(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p32(void volatile* obj) { @@ -4532,9 +6620,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p64(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p64(void volatile* obj) { - void* val = (void*)__iso_volatile_load64(obj); + void* value = (void*)__iso_volatile_load64(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p64(void volatile* obj) { diff --git a/src/Compilation.zig b/src/Compilation.zig index d62856b0111be20def4ebf322ee0f58831995161..df6fc7b06b192553ca5faed923c4a9b4406814f5 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2134,6 +2134,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, comp.config.any_fuzz = any_fuzz; if (opt_zcu) |zcu| { + // Finish initializing the `zcu` after the fields on `comp` have been initialized. + zcu.initAfterCompilation(); + // Populate `zcu.module_roots`. const active = zcu.acquire(); defer active.release(); diff --git a/src/InternPool.zig b/src/InternPool.zig index 5a28a997418a52a40a06c324d610348ab5c17800..8502055c372f2fb915be32133ee6a8be60916e4b 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -4193,7 +4193,7 @@ pub const Index = enum(u32) { }; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// Tag to encoding mapping to facilitate fancy debug printing for this type. fn dbHelper(self: *Index, tag_to_encoding_map: *struct { const DataIsIndex = struct { data: Index }; @@ -4219,26 +4219,17 @@ pub const Index = enum(u32) { type_inferred_error_set: DataIsIndex, simple_type: void, type_function: struct { - const @"data.flags.has_comptime_bits" = opaque {}; - const @"data.flags.has_noalias_bits" = opaque {}; - const @"data.flags.cc.extraLen()" = opaque {}; const @"data.params_len" = opaque {}; data: *Tag.TypeFunction, - @"trailing.comptime_bits.len": *@"data.flags.has_comptime_bits", - @"trailing.noalias_bits.len": *@"data.flags.has_noalias_bits", - @"trailing.cc_bits.len": *@"data.flags.cc.extraLen()", @"trailing.param_types.len": *@"data.params_len", - trailing: struct { comptime_bits: []u32, noalias_bits: []u32, cc_bits: []u32, param_types: []Index }, + trailing: struct { param_types: []Index }, }, type_tuple: struct { const @"data.fields_len" = opaque {}; data: *TypeTuple, @"trailing.types.len": *@"data.fields_len", @"trailing.values.len": *@"data.fields_len", - trailing: struct { - types: []Index, - values: []Index, - }, + trailing: struct { types: []Index, values: []Index }, }, type_struct: struct { data: *Tag.TypeStruct }, @@ -4350,7 +4341,7 @@ pub const Index = enum(u32) { const encoding = @field(Tag.encodings, tag_name); if (@hasField(@TypeOf(encoding), "trailing")) { const trailing_info = @typeInfo(encoding.trailing).@"struct"; - for (trailing_info.field_names, trailing_info.field_types) |field_name, field_type| { + for (trailing_info.field_names, trailing_info.field_types) |trailing_field_name, trailing_field_type| { struct { fn checkConfig(name: []const u8) void { if (!@hasField(@TypeOf(encoding.config), name)) @compileError("missing field: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ ".config.@\"" ++ name ++ "\""); @@ -4359,22 +4350,30 @@ pub const Index = enum(u32) { } fn checkField(name: []const u8, Type: type) void { switch (@typeInfo(Type)) { - .int => {}, - .@"enum" => {}, - .@"struct" => |info| assert(info.layout == .@"packed"), + .int, .@"enum" => return, + .@"struct" => |info| switch (info.layout) { + .auto => unreachable, + .@"extern" => { + for (info.field_names, info.field_types) |field_name, field_type| checkField(name ++ "." ++ field_name, field_type); + return; + }, + .@"packed" => return, + }, .optional => |info| { checkConfig(name ++ ".?"); checkField(name ++ ".?", info.child); + return; }, - .pointer => |info| { - assert(info.size == .slice); + .pointer => |info| if (info.size == .slice) { checkConfig(name ++ ".len"); checkField(name ++ "[0]", info.child); + return; }, - else => @compileError("unsupported type: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ "." ++ name ++ ": " ++ @typeName(Type)), + else => {}, } + @compileError("unsupported type: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ "." ++ name ++ ": " ++ @typeName(Type)); } - }.checkField("trailing." ++ field_name, field_type); + }.checkField("trailing." ++ trailing_field_name, trailing_field_type); } } }, @@ -5186,17 +5185,18 @@ pub const Tag = enum(u8) { .trailing = struct { param_comptime_bits: ?[]u32, param_noalias_bits: ?[]u32, - param_cc_bits: ?[]u32, - param_type: []Index, + spirv_kernel_options: ?extern struct { x: u32, y: u32, z: u32 }, + spirv_mesh_options: ?extern struct { max_primitives: u32, max_vertices: u32 }, + param_types: []Index, }, .config = .{ .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits", .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32", .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits", .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32", - .@"trailing.param_cc_bits.?" = .@"payload.flags.cc.extraLen() != 0", - .@"trailing.param_cc_bits.?.len" = .@"payload.flags.cc.extraLen()", - .@"trailing.param_type.len" = .@"payload.params_len", + .@"trailing.spirv_kernel_options.?" = .@"payload.flags.cc.tag == .spirv_kernel or payload.flags.cc.tag == .spirv_task", + .@"trailing.spirv_mesh_options.?" = .@"payload.flags.cc.tag == .spirv_mesh", + .@"trailing.param_types.len" = .@"payload.params_len", }, }, @@ -5225,7 +5225,7 @@ pub const Tag = enum(u8) { .@"trailing.field_defaults.?" = .@"payload.flags.any_field_defaults", .@"trailing.field_defaults.?.len" = .@"payload.fields_len", .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns", - .@"trailing.field_aligns.?.len" = .@"payload.fields_len", + .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) / 4", .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields", .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32", .@"trailing.field_runtime_order.?" = .@"payload.flags.layout == .auto", @@ -5254,7 +5254,7 @@ pub const Tag = enum(u8) { .@"trailing.captures.?.len" = .@"trailing.captures_len.?", .@"trailing.field_types.len" = .@"payload.fields_len", .@"trailing.field_aligns.?" = .@"payloads.flags.any_field_aligns", - .@"trailing.field_aligns.?.len" = .@"payload.fields_len", + .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) / 4", }, }, .type_union_packed_auto = union_packed_encoding, diff --git a/src/Sema.zig b/src/Sema.zig index 129b9104d385499e8443b4fc45dcf6c2e26497e8..2181fa563b9e9dec42b1123cc3b738874df64ca7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8501,6 +8501,7 @@ const calling_conventions_supporting_var_args = [_]std.lang.CallingConvention.Ta .x86_64_win, .x86_sysv, .x86_win, + .x86_mingw, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win, @@ -25675,7 +25676,6 @@ pub fn explainWhyTypeIsNotExtern( .@"opaque", .bool, - .float, .@"anyframe", => unreachable, // these *are* allowed @@ -25684,6 +25684,7 @@ pub fn explainWhyTypeIsNotExtern( try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{}); }, + .float => try sema.errNote(src_loc, msg, "'{f}' is not extern compatible on this target", .{ty.fmt(pt)}), .pointer => if (ty.isSlice(zcu)) { try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); } else { @@ -29657,7 +29658,7 @@ fn coerceVarArgParam( .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), .float => float: { const target = zcu.getTarget(); - const double_bits = target.cTypeBitSize(.double); + const double_bits = target.cTypeBitSize(.double) orelse break :float inst; const inst_bits = uncasted_ty.floatBits(target); if (inst_bits >= double_bits) break :float inst; switch (double_bits) { @@ -29673,21 +29674,21 @@ fn coerceVarArgParam( if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .int, .unsigned => .uint, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }) orelse break :int inst) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_int, .unsigned => .c_uint, }, inst, inst_src); if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .long, .unsigned => .ulong, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_long, .unsigned => .c_ulong, }, inst, inst_src); if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .longlong, .unsigned => .ulonglong, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_longlong, .unsigned => .c_ulonglong, }, inst, inst_src); diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig index ef8e24c86744023e52bef9d9c2d0f1f029936852..b3de4f8433a768a6a5c4c174fb300f1a899edf64 100644 --- a/src/Sema/type_resolution.zig +++ b/src/Sema/type_resolution.zig @@ -364,7 +364,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const a = struct_obj.field_aligns.get(ip)[field_idx]; if (a != .none) break :a a; } - break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); + break :a field_ty.abiAlignment(zcu); }; align_out.* = field_align; if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) { diff --git a/src/Type.zig b/src/Type.zig index e60726ced3ff48df988eff1505786071c596ff2a..466a707b998294905c7d068acc1f2c98193232dc 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -957,12 +957,27 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { if (vector_type.len == 0) return .@"1"; switch (zcu.comp.getZigBackend()) { else => { - const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu)); + const elem_ty: Type = .fromInterned(vector_type.child); + switch (if (elem_ty.isRuntimeFloat()) + std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target)) + else + .hard) { + .hard => {}, + .soft => return elem_ty.abiAlignment(zcu), + } + const elem_bits: u32 = @intCast(elem_ty.bitSize(zcu)); if (elem_bits == 0) return .@"1"; const bytes = ((elem_bits * vector_type.len) + 7) / 8; - return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); + const arch = target.cpu.arch; + return .fromByteUnits(std.math.ceilPowerOfTwoAssert( + u32, + if (arch.isArm() or arch.isAARCH64() or arch == .s390x) + @min(bytes, target.stackAlignment()) + else + bytes, + )); }, - .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).defaultStructFieldAlignment(.auto, zcu), + .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).abiAlignment(zcu), .stage2_x86_64 => { if (vector_type.child == .bool_type) { if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; @@ -1018,19 +1033,33 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { .c_ulonglong => cTypeAlign(target, .ulonglong), .c_longdouble => cTypeAlign(target, .longdouble), - .f16 => .@"2", - .f32 => if (target.os.tag == .opengl) .@"4" else cTypeAlign(target, .float), - .f64 => if (target.os.tag == .opengl) .@"8" else switch (target.cTypeBitSize(.double)) { - 64 => cTypeAlign(target, .double), - else => .@"8", - }, - .f80 => switch (target.cTypeBitSize(.longdouble)) { - 80 => cTypeAlign(target, .longdouble), - else => Type.u80.abiAlignment(zcu), - }, - .f128 => switch (target.cTypeBitSize(.longdouble)) { - 128 => cTypeAlign(target, .longdouble), - else => .@"16", + .f16 => .fromByteUnits(std.zig.target.intAlignment(target, 16)), // repr: u16 + .f32 => if (target.cTypeBitSize(.float) == 32) + cTypeAlign(target, .float) // abi: c_float, + else + .fromByteUnits(std.zig.target.intAlignment(target, 32)), // repr: u32, + .f64 => if (target.cTypeBitSize(.double) == 64) + cTypeAlign(target, .double) // abi: c_double, + else + .fromByteUnits(std.zig.target.intAlignment(target, 64)), // repr: u64, + .f80 => if (target.cTypeBitSize(.longdouble) == 80) + cTypeAlign(target, .longdouble) // abi: c_longdouble, + else + .fromByteUnits(switch (std.zig.target.compilerRtFloatAbi(target, 80)) { + .hard => std.zig.target.intAlignment(target, 80), // repr: u80, + .soft => @max( + std.zig.target.intAlignment(target, 64), // mantissa: u64, + std.zig.target.intAlignment(target, 16), // exponent: u16, + ), + }), + .f128 => if (target.cTypeBitSize(.longdouble) == 128) + cTypeAlign(target, .longdouble) // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 128)) { + .hard => if (target.cpu.arch.isX86()) + .@"16" // abi: c___float128, + else + .fromByteUnits(std.zig.target.intAlignment(target, 128)), // repr: u128, + .soft => .fromByteUnits(std.zig.target.intAlignment(target, 64)), // lo: u64, hi: u64, }, .generic_poison => unreachable, @@ -1111,7 +1140,13 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { .vector_type => |vec| { const elem_ty: Type = .fromInterned(vec.child); const bytes = switch (zcu.comp.getZigBackend()) { - else => @divCeil(vec.len * elem_ty.bitSize(zcu), 8), + else => switch (if (elem_ty.isRuntimeFloat()) + std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target)) + else + .hard) { + .hard => @divCeil(vec.len * elem_ty.bitSize(zcu), 8), + .soft => vec.len * elem_ty.abiSize(zcu), + }, .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu), .stage2_x86_64 => switch (elem_ty.toIntern()) { .bool_type => @divCeil(vec.len, 8), @@ -1167,25 +1202,44 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu), .usize, .isize => ptrAbiSize(target), - .c_char => target.cTypeByteSize(.char), - .c_short => target.cTypeByteSize(.short), - .c_ushort => target.cTypeByteSize(.ushort), - .c_int => target.cTypeByteSize(.int), - .c_uint => target.cTypeByteSize(.uint), - .c_long => target.cTypeByteSize(.long), - .c_ulong => target.cTypeByteSize(.ulong), - .c_longlong => target.cTypeByteSize(.longlong), - .c_ulonglong => target.cTypeByteSize(.ulonglong), - .c_longdouble => target.cTypeByteSize(.longdouble), + .c_char => target.cTypeByteSize(.char).?, + .c_short => target.cTypeByteSize(.short).?, + .c_ushort => target.cTypeByteSize(.ushort).?, + .c_int => target.cTypeByteSize(.int).?, + .c_uint => target.cTypeByteSize(.uint).?, + .c_long => target.cTypeByteSize(.long).?, + .c_ulong => target.cTypeByteSize(.ulong).?, + .c_longlong => target.cTypeByteSize(.longlong).?, + .c_ulonglong => target.cTypeByteSize(.ulonglong).?, + .c_longdouble => target.cTypeByteSize(.longdouble).?, - .f16 => 2, - .f32 => 4, - .f64 => 8, - .f80 => switch (target.cTypeBitSize(.longdouble)) { - 80 => target.cTypeByteSize(.longdouble), - else => Type.u80.abiSize(zcu), + .f16 => std.zig.target.intByteSize(target, 16), // repr: u16 + .f32 => if (target.cTypeBitSize(.float) == 32) + target.cTypeByteSize(.float).? // abi: c_float, + else + std.zig.target.intByteSize(target, 32), // repr: u32, + .f64 => if (target.cTypeBitSize(.double) == 64) + target.cTypeByteSize(.double).? // abi: c_double, + else + std.zig.target.intByteSize(target, 64), // repr: u64, + .f80 => if (target.cTypeBitSize(.longdouble) == 80) + target.cTypeByteSize(.longdouble).? // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 80)) { + .hard => std.zig.target.intByteSize(target, 80), // repr: u80, + .soft => ty.abiAlignment(zcu).forward( + std.zig.target.intByteSize(target, 64) + // mantissa: u64, + std.zig.target.intByteSize(target, 16), // exponent: u16 + ), + }, + .f128 => if (target.cTypeBitSize(.longdouble) == 128) + target.cTypeByteSize(.longdouble).? // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 128)) { + .hard => if (target.cpu.arch.isX86()) + 16 // abi: c___float128, + else + std.zig.target.intByteSize(target, 128), // repr: u128, + .soft => std.zig.target.intByteSize(target, 64) * 2, // lo: u64, hi: u64, }, - .f128 => 16, .anyopaque => unreachable, .generic_poison => unreachable, @@ -1733,7 +1787,7 @@ pub fn isInt(self: Type, zcu: *const Zcu) bool { /// Returns true if and only if the type is a fixed-width, signed integer. pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool { return switch (ty.toIntern()) { - .c_char_type => zcu.getTarget().cCharSignedness() == .signed, + .c_char_type => zcu.getTarget().cCharSignedness().? == .signed, .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true, else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { .int_type => |int_type| int_type.signedness == .signed, @@ -1745,7 +1799,7 @@ pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool { /// Returns true if and only if the type is a fixed-width, unsigned integer. pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool { return switch (ty.toIntern()) { - .c_char_type => zcu.getTarget().cCharSignedness() == .unsigned, + .c_char_type => zcu.getTarget().cCharSignedness().? == .unsigned, .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true, else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { .int_type => |int_type| int_type.signedness == .unsigned, @@ -1776,15 +1830,15 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { }, .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, - .c_char_type => return .{ .signedness = zcu.getTarget().cCharSignedness(), .bits = target.cTypeBitSize(.char) }, - .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short) }, - .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort) }, - .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int) }, - .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint) }, - .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long) }, - .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong) }, - .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong) }, - .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) }, + .c_char_type => return .{ .signedness = target.cCharSignedness().?, .bits = target.cTypeBitSize(.char).? }, + .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short).? }, + .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort).? }, + .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int).? }, + .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint).? }, + .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long).? }, + .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong).? }, + .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong).? }, + .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong).? }, else => switch (ip.indexToKey(ty.toIntern())) { .int_type => |int_type| return int_type, .struct_type => { @@ -1882,7 +1936,7 @@ pub fn floatBits(ty: Type, target: *const Target) u16 { .f64_type => 64, .f80_type => 80, .f128_type, .comptime_float_type => 128, - .c_longdouble_type => target.cTypeBitSize(.longdouble), + .c_longdouble_type => target.cTypeBitSize(.longdouble).?, else => unreachable, }; @@ -2147,13 +2201,6 @@ pub fn isVector(ty: Type, zcu: *const Zcu) bool { return ty.zigTypeTag(zcu) == .vector; } -/// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len. -pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 { - if (!ty.isVector(zcu)) return 0; - const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type; - return v.len * Type.fromInterned(v.child).bitSize(zcu); -} - pub fn isArrayOrVector(ty: Type, zcu: *const Zcu) bool { return switch (ty.zigTypeTag(zcu)) { .array, .vector => true, @@ -2416,34 +2463,6 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment }; } -/// Returns the alignment a struct field of type `field_ty` will be given if no alignment is -/// explicitly specified. However, in an `extern struct`, a higher alignment may be available due -/// to the struct's full layout (i.e. a field might coincidentally be more aligned). -/// -/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`. -pub fn defaultStructFieldAlignment( - field_ty: Type, - layout: std.lang.Type.ContainerLayout, - zcu: *const Zcu, -) Alignment { - const overalign_big_int = switch (layout) { - .@"packed" => unreachable, - .auto => zcu.getTarget().ofmt == .c, - .@"extern" => true, - }; - const abi_align = field_ty.abiAlignment(zcu); - assert(abi_align != .none); - // We check for anything over 64 here, because the C backend will lower e.g. u64 to a 128-bit - // integer, which has 16-byte alignment. - if (overalign_big_int and - ((field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits > 64) or - (field_ty.toIntern() == .f80_type and zcu.getTarget().cTypeBitSize(.longdouble) != 80))) - { - return abi_align.maxStrict(if (zcu.getTarget().cpu.arch == .s390x) .@"8" else .@"16"); - } - return abi_align; -} - pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value { const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { @@ -2961,8 +2980,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator } const actual_field_align = switch (field_align) { .none => switch (ip.indexToKey(aggregate_ty.toIntern())) { - .tuple_type, .union_type => field_ty.abiAlignment(zcu), - .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu), + .struct_type, .tuple_type, .union_type => field_ty.abiAlignment(zcu), .ptr_type => Type.usize.abiAlignment(zcu), else => unreachable, }, @@ -3122,7 +3140,6 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .@"opaque", .bool, - .float, .@"anyframe", => true, @@ -3144,6 +3161,10 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool 24, 48 => zcu.getTarget().cpu.arch == .ez80, else => false, }, + .float => switch (ty.floatBits(zcu.getTarget())) { + else => true, + 80 => zcu.getTarget().cTypeBitSize(.longdouble) == 80, + }, .@"fn" => { if (position != .other) return false; return validateExternCallconv(ty.fnCallingConvention(zcu)); @@ -3600,5 +3621,5 @@ pub fn smallestUnsignedBits(max: u64) u16 { pub const packed_struct_layout_version = 2; fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment { - return Alignment.fromByteUnits(target.cTypeAlignment(c_type)); + return .fromByteUnits(target.cTypeAlignment(c_type).?); } diff --git a/src/Value.zig b/src/Value.zig index dfc124659c3f6d9fb3be15430a5734ff2a3fe194..f6905eb4b55d11df4c1610c9c8e41475cd4fe522 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -611,12 +611,7 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T { return switch (zcu.intern_pool.indexToKey(val.toIntern())) { .int => |int| switch (int.storage) { .big_int => |big_int| big_int.toFloat(T, .nearest_even)[0], - inline .u64, .i64 => |x| { - if (T == f80) { - @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); - } - return @floatFromInt(x); - }, + inline .u64, .i64 => |x| @floatFromInt(x), }, .float => |float| switch (float.storage) { inline else => |x| @floatCast(x), diff --git a/src/Zcu.zig b/src/Zcu.zig index d3c180b63eb8854ec8598cdb3099bba7a41fb2b3..875ffd44b29c92738f12e3cf32f300301edf2d7d 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -2825,6 +2825,11 @@ pub const CompileError = error{ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { try zcu.intern_pool.init(gpa, io, thread_count); +} + +/// It is valid to not call this function before `deinit` in error paths. +/// Requires the fields on `zcu.comp` to already be initialized. +pub fn initAfterCompilation(zcu: *Zcu) void { zcu.initTracyPlots(); } @@ -4612,43 +4617,26 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .m68k_rtd, .m68k_interrupt, .msp430_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_aapcs_vfp, - => |opts| opts.incoming_stack_alignment == null, - .arc_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .microblaze_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .mips_interrupt, .mips64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .riscv32_interrupt, .riscv64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .sh_interrupt, - => |opts| opts.incoming_stack_alignment == null, + .avr_interrupt, + .avr_signal, + .ez80_tiflags, + .naked, + => true, // incoming stack alignment supported .x86_sysv, .x86_win, + .x86_mingw, .x86_stdcall, - => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, - - .avr_interrupt, - .avr_signal, - => true, - - .ez80_tiflags => true, - - .naked => true, + => |opts| opts.register_params == 0, // incoming stack alignment supported else => false, }; @@ -4673,6 +4661,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .stage2_x86 => switch (cc) { .x86_sysv, .x86_win, + .x86_mingw, => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, .naked => true, else => false, diff --git a/src/codegen.zig b/src/codegen.zig index a691b36a4811f7cf127de20aa50d33e2b6e8d700..4ad10d48c05c59608f06956209f7f9b66a6d2775 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1124,6 +1124,201 @@ pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: }; } +pub const FlattenedItem = struct { offset: u64, type: ?Type }; +pub fn flattenType(items_buf: []FlattenedItem, ty: Type, zcu: *Zcu, opts: struct { + offset: u64 = 0, + allow_arrays: bool = true, + fn increaseOffset(opts: @This(), offset: u64) @This() { + return .{ + .offset = opts.offset + offset, + .allow_arrays = opts.allow_arrays, + }; + } +}) ?[]FlattenedItem { + const ip = &zcu.intern_pool; + switch (ip.indexToKey(ty.toIntern())) { + .int_type => |int_type| { + if (int_type.bits == 0) return items_buf[0..0]; + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .ptr_type => |ptr_type| switch (ptr_type.flags.size) { + .one, .many, .c => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .slice => { + if (items_buf.len < 2) return null; + const items = items_buf[0..2]; + const ptr_field_ty = ty.slicePtrFieldType(zcu); + items.* = .{ + .{ .offset = opts.offset, .type = ptr_field_ty }, + .{ .offset = opts.offset + ptr_field_ty.abiSize(zcu), .type = .usize }, + }; + return items; + }, + }, + .array_type => |array_type| { + const len = array_type.lenIncludingSentinel(); + if (len == 0) return items_buf[0..0]; + const elem_ty: Type = .fromInterned(array_type.child); + const elem_items = flattenType(items_buf, elem_ty, zcu, opts) orelse return null; + if (elem_items.len == 0) return items_buf[0..0]; + if (!opts.allow_arrays) return null; + const items_len, const items_overflow = @mulWithOverflow(elem_items.len, len); + if (items_overflow != 0 or items_buf.len < items_len) return null; + var items_index = elem_items.len; + const elem_size = elem_ty.abiSize(zcu); + var elem_offset: u64 = elem_size; + while (items_index != items_len) : ({ + items_index += elem_items.len; + elem_offset += elem_size; + }) for (items_buf[items_index..][0..elem_items.len], elem_items) |*item, elem_item| { + item.* = .{ .offset = elem_offset + elem_item.offset, .type = elem_item.type }; + }; + return items_buf[0..@intCast(items_len)]; + }, + .vector_type => |vector_type| { + if (vector_type.len == 0) return items_buf[0..0]; + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .opt_type, .error_union_type => return null, + .simple_type => |simple_type| switch (simple_type) { + .f16, + .f32, + .f64, + .f80, + .f128, + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + .c_longdouble, + .bool, + .anyerror, + => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .anyopaque, .noreturn => return null, + .void, + .type, + .comptime_int, + .comptime_float, + .null, + .undefined, + .enum_literal, + => return items_buf[0..0], + .adhoc_inferred_error_set, .generic_poison => unreachable, + }, + .struct_type => { + const loaded_struct = ip.loadStructType(ty.toIntern()); + switch (loaded_struct.layout) { + .auto, .@"extern" => {}, + .@"packed" => return flattenType(items_buf, .fromInterned( + loaded_struct.packed_backing_int_type, + ), zcu, opts), + } + var items_len: usize = 0; + var offset: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_offset = loaded_struct.field_offsets.get(ip)[field_index]; + if (field_offset - offset > 0 and + (items_len == 0 or items_buf[items_len - 1].type != null)) + { + if (items_len == items_buf.len) return null; + items_buf[items_len] = .{ .offset = offset, .type = null }; + items_len += 1; + } + items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( + field_offset, + )) orelse return null).len; + offset = field_offset + field_ty.abiSize(zcu); + } + if (ty.abiSize(zcu) - offset > 0 and + (items_len == 0 or items_buf[items_len - 1].type != null)) + { + if (items_len == items_buf.len) return null; + items_buf[items_len] = .{ .offset = offset, .type = null }; + items_len += 1; + } + return items_buf[0..items_len]; + }, + .tuple_type => |tuple_type| { + if (items_buf.len < tuple_type.types.len) return null; + var items_len: usize = 0; + var offset: u64 = 0; + for (tuple_type.types.get(ip)) |field_ty_ip| { + const field_ty: Type = .fromInterned(field_ty_ip); + offset = field_ty.abiAlignment(zcu).forward(offset); + items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( + offset, + )) orelse return null).len; + offset += field_ty.abiSize(zcu); + } + return items_buf[0..items_len]; + }, + .union_type => { + const loaded_union = ip.loadUnionType(ty.toIntern()); + return switch (loaded_union.layout) { + .auto, .@"extern" => return null, + .@"packed" => return flattenType(items_buf, .fromInterned( + loaded_union.packed_backing_int_type, + ), zcu, opts), + }; + }, + .opaque_type, .spirv_type, .func_type => return null, + .enum_type => return flattenType(items_buf, .fromInterned( + ip.loadEnumType(ty.toIntern()).int_tag_type, + ), zcu, opts), + .error_set_type, .inferred_error_set_type => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .anyframe_type, + // values, not types + .undef, + .simple_value, + .@"extern", + .func, + .int, + .err, + .error_union, + .enum_literal, + .enum_tag, + .float, + .ptr, + .slice, + .opt, + .aggregate, + .un, + .bitpack, + // memoization, not types + .memoized_call, + => unreachable, + } +} + test { _ = aarch64; } diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 30387bfe8a37719577b57391f6f270e71e8238e2..1050b8fb0eb1425205f04b7440640ec55d6cf69a 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -2099,7 +2099,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "truncf", 64 => "trunc", 80 => "__truncx", - 128 => "truncq", + 128 => "truncf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2113,7 +2113,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "floorf", 64 => "floor", 80 => "__floorx", - 128 => "floorq", + 128 => "floorf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2431,7 +2431,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmodf", 64 => "fmod", 80 => "__fmodx", - 128 => "fmodq", + 128 => "fmodf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2599,7 +2599,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmaxf", 64 => "fmax", 80 => "__fmaxx", - 128 => "fmaxq", + 128 => "fmaxf128", }, .min => switch (bits) { else => unreachable, @@ -2607,7 +2607,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fminf", 64 => "fmin", 80 => "__fminx", - 128 => "fminq", + 128 => "fminf128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -4055,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "sqrtf", 64 => "sqrt", 80 => "__sqrtx", - 128 => "sqrtq", + 128 => "sqrtf128", }, .floor => switch (bits) { else => unreachable, @@ -4063,7 +4063,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "floorf", 64 => "floor", 80 => "__floorx", - 128 => "floorq", + 128 => "floorf128", }, .ceil => switch (bits) { else => unreachable, @@ -4071,7 +4071,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "ceilf", 64 => "ceil", 80 => "__ceilx", - 128 => "ceilq", + 128 => "ceilf128", }, .round => switch (bits) { else => unreachable, @@ -4079,7 +4079,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "roundf", 64 => "round", 80 => "__roundx", - 128 => "roundq", + 128 => "roundf128", }, .trunc_float => switch (bits) { else => unreachable, @@ -4087,7 +4087,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "truncf", 64 => "trunc", 80 => "__truncx", - 128 => "truncq", + 128 => "truncf128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -4147,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "sinf", 64 => "sin", 80 => "__sinx", - 128 => "sinq", + 128 => "sinf128", }, .cos => switch (bits) { else => unreachable, @@ -4155,7 +4155,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "cosf", 64 => "cos", 80 => "__cosx", - 128 => "cosq", + 128 => "cosf128", }, .tan => switch (bits) { else => unreachable, @@ -4163,7 +4163,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "tanf", 64 => "tan", 80 => "__tanx", - 128 => "tanq", + 128 => "tanf128", }, .exp => switch (bits) { else => unreachable, @@ -4171,7 +4171,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "expf", 64 => "exp", 80 => "__expx", - 128 => "expq", + 128 => "expf128", }, .exp2 => switch (bits) { else => unreachable, @@ -4179,7 +4179,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "exp2f", 64 => "exp2", 80 => "__exp2x", - 128 => "exp2q", + 128 => "exp2f128", }, .log => switch (bits) { else => unreachable, @@ -4187,7 +4187,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "logf", 64 => "log", 80 => "__logx", - 128 => "logq", + 128 => "logf128", }, .log2 => switch (bits) { else => unreachable, @@ -4195,7 +4195,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "log2f", 64 => "log2", 80 => "__log2x", - 128 => "log2q", + 128 => "log2f128", }, .log10 => switch (bits) { else => unreachable, @@ -4203,7 +4203,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "log10f", 64 => "log10", 80 => "__log10x", - 128 => "log10q", + 128 => "log10f128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -7118,7 +7118,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmaf", 64 => "fma", 80 => "__fmax", - 128 => "fmaq", + 128 => "fmaf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -12388,7 +12388,7 @@ pub const CallAbiIterator = struct { .f32 => .single, .f64 => .double, .f128 => .quad, - .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) { + .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble).?) { else => unreachable, 64 => .double, 80 => null, diff --git a/src/codegen/aarch64/abi.zig b/src/codegen/aarch64/abi.zig index dcd192da8395fc6fca07c101aebff596bc4e99cc..863a45e2d4bded294e263edff46787942cbcb31b 100644 --- a/src/codegen/aarch64/abi.zig +++ b/src/codegen/aarch64/abi.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assert = std.debug.assert; const std = @import("std"); const InternPool = @import("../../InternPool.zig"); const Type = @import("../../Type.zig"); @@ -35,7 +35,12 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { if (bit_size > 64) return .double_integer; return .integer; }, - .int, .@"enum", .error_set, .float, .bool => return .byval, + .int, .@"enum", .error_set, .bool => return .byval, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64, 128 => .byval, + 80 => .double_integer, + }, .vector => { const bit_size = ty.bitSize(zcu); // TODO is this controlled by a cpu feature? diff --git a/src/codegen/arm/abi.zig b/src/codegen/arm/abi.zig index 14acccbb7963991a3c9c201bcebaeb9218af7ff8..bd767560f1c0ac8fb3d5b8b6eed5956ea8e8253d 100644 --- a/src/codegen/arm/abi.zig +++ b/src/codegen/arm/abi.zig @@ -39,7 +39,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; - if (ty.abiAlignment(zcu).compare(.gt, .@"32")) { + if (ty.abiAlignment(zcu).compare(.gt, .@"4")) { return Class.arrSize(bit_size, 64); } @@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; - if (union_obj.alignment.compareStrict(.gt, .@"32")) { + if (union_obj.alignment.compareStrict(.gt, .@"4")) { return Class.arrSize(bit_size, 64); } @@ -73,14 +73,16 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { } return Class.arrSize(bit_size, 32); }, - .bool, .float => return .byval, + .bool => return .byval, .int => { - // TODO this is incorrect for _BitInt(128) but implementing - // this correctly makes implementing compiler-rt impossible. - // const bit_size = ty.bitSize(zcu); - // if (bit_size > 64) return .memory; + if (ctx == .ret and ty.intInfo(zcu).bits > 64) return .memory; return .byval; }, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64 => .byval, + 80, 128 => .{ .i64_array = 2 }, + }, .@"enum", .error_set => { const bit_size = ty.bitSize(zcu); if (bit_size > 64) return .memory; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 9ecd3a4e0b1f4483c878e056cf3786bccafed62b..5ab86a9a5fad9e1a4391053bd5e1af970de1feeb 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -164,7 +164,8 @@ const BlockData = struct { const LocalType = struct { type: Type, - alignment: Alignment, + alignment: Alignment = .none, + array_len: u2 = 1, }; const LocalIndex = u16; @@ -184,13 +185,11 @@ const ValueRenderLocation = enum { } }; -const BuiltinInfo = enum { none, bits }; +const BuiltinInfo = enum { none, bits, bits_none, big_temp_bits }; const reserved_idents = std.StaticStringMap(void).initComptime(.{ // C language - .{ "alignas", { - @setEvalBranchQuota(4000); - } }, + .{ "alignas", {} }, .{ "alignof", {} }, .{ "asm", {} }, .{ "atomic_bool", {} }, @@ -302,7 +301,100 @@ const reserved_idents = std.StaticStringMap(void).initComptime(.{ // stddef.h .{ "offsetof", {} }, + // math.h (only symbols exported by compiler-rt) + .{ "ceil", {} }, + .{ "ceilf", {} }, + .{ "ceilf128", {} }, + .{ "ceill", {} }, + .{ "cos", {} }, + .{ "cosf", {} }, + .{ "cosf128", {} }, + .{ "cosl", {} }, + .{ "exp", {} }, + .{ "exp2", {} }, + .{ "exp2f", {} }, + .{ "exp2f128", {} }, + .{ "exp2l", {} }, + .{ "expf", {} }, + .{ "expf128", {} }, + .{ "expl", {} }, + .{ "fabs", {} }, + .{ "fabsf", {} }, + .{ "fabsf128", {} }, + .{ "fabsl", {} }, + .{ "floor", {} }, + .{ "floorf", {} }, + .{ "floorf128", {} }, + .{ "floorl", {} }, + .{ "fma", {} }, + .{ "fmaf", {} }, + .{ "fmaf128", {} }, + .{ "fmal", {} }, + .{ "fmax", {} }, + .{ "fmaxf", {} }, + .{ "fmaxf128", {} }, + .{ "fmaxl", {} }, + .{ "fmin", {} }, + .{ "fminf", {} }, + .{ "fminf128", {} }, + .{ "fminl", {} }, + .{ "fmod", {} }, + .{ "fmodf", {} }, + .{ "fmodf128", {} }, + .{ "fmodl", {} }, + .{ "log", {} }, + .{ "log10", {} }, + .{ "log10f", {} }, + .{ "log10f128", {} }, + .{ "log10l", {} }, + .{ "log2", {} }, + .{ "log2f", {} }, + .{ "log2f128", {} }, + .{ "log2l", {} }, + .{ "logf", {} }, + .{ "logf128", {} }, + .{ "logl", {} }, + .{ "round", {} }, + .{ "roundf", {} }, + .{ "roundf128", {} }, + .{ "roundl", {} }, + .{ "sin", {} }, + .{ "sincos", {} }, + .{ "sincosf", {} }, + .{ "sincosf128", {} }, + .{ "sincosl", {} }, + .{ "sinf", {} }, + .{ "sinf128", {} }, + .{ "sinl", {} }, + .{ "sqrt", {} }, + .{ "sqrtf", {} }, + .{ "sqrtf128", {} }, + .{ "sqrtl", {} }, + .{ "tan", {} }, + .{ "tanf", {} }, + .{ "tanf128", {} }, + .{ "tanl", {} }, + .{ "trunc", {} }, + .{ "truncf", {} }, + .{ "truncf128", {} }, + .{ "truncl", {} }, + // windows.h + .{"DUMMYSTRUCTNAME"}, + .{"DUMMYSTRUCTNAME2"}, + .{"DUMMYSTRUCTNAME3"}, + .{"DUMMYSTRUCTNAME4"}, + .{"DUMMYSTRUCTNAME5"}, + .{"DUMMYSTRUCTNAME6"}, + .{"DUMMYUNIONNAME"}, + .{"DUMMYUNIONNAME2"}, + .{"DUMMYUNIONNAME3"}, + .{"DUMMYUNIONNAME4"}, + .{"DUMMYUNIONNAME5"}, + .{"DUMMYUNIONNAME6"}, + .{"DUMMYUNIONNAME7"}, + .{"DUMMYUNIONNAME8"}, + .{"DUMMYUNIONNAME9"}, .{ "max", {} }, .{ "min", {} }, }); @@ -316,13 +408,6 @@ fn isReservedIdent(ident: []const u8) bool { } } - // windows.h - if (mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or - mem.startsWith(u8, ident, "DUMMYUNIONNAME")) - { - return true; - } - // CType if (mem.startsWith(u8, ident, "enum__") or mem.startsWith(u8, ident, "bitpack__") or @@ -469,10 +554,7 @@ pub const Function = struct { } fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue { - return f.allocAlignedLocal(inst, .{ - .type = ty, - .alignment = .none, - }); + return f.allocAlignedLocal(inst, .{ .type = ty }); } /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should @@ -564,10 +646,6 @@ pub const Function = struct { return f.dg.renderType(w, ty); } - fn renderIntCast(f: *Function, w: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { - return f.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location); - } - fn fmtIntLiteralDec(f: *Function, val: Value) !std.fmt.Alt(FormatIntLiteralContext, formatIntLiteral) { return f.dg.fmtIntLiteralDec(val, .other); } @@ -672,7 +750,9 @@ pub const DeclGen = struct { // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. const ptr_ty: Type = .fromInterned(uav.orig_ty); if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { - return dg.renderUndefValue(w, ptr_ty, location); + try w.writeByte('('); + try dg.renderOpvPointer(w, ptr_ty, location); + return w.writeByte(')'); } switch (ip.indexToKey(uav.val)) { @@ -737,8 +817,10 @@ pub const DeclGen = struct { // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).resolved.?.type); const ptr_ty = try pt.navPtrType(owner_nav); - if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { - return dg.renderUndefValue(w, ptr_ty, location); + if (nav_ty.zigTypeTag(zcu) != .@"opaque" and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { + try w.writeByte('('); + try dg.renderOpvPointer(w, ptr_ty, location); + return w.writeByte(')'); } // We shouldn't cast C function pointers as this is UB (when you call @@ -758,6 +840,26 @@ pub const DeclGen = struct { if (need_cast) try w.writeByte(')'); } + fn renderOpvPointer( + dg: *DeclGen, + w: *Writer, + ptr_ty: Type, + location: ValueRenderLocation, + ) Error!void { + const zcu = dg.pt.zcu; + const target = zcu.getTarget(); + try w.writeByte('('); + try dg.renderType(w, ptr_ty); + return w.print("){f}", .{fmtUnsignedIntLiteralSmall( + target, + .uintptr_t, + ptr_ty.ptrAlignment(zcu).forward(undefPattern(u64) >> @intCast(64 - target.ptrBitWidth())), + location == .static_initializer, + 16, + .lower, + )}); + } + fn renderPointer( dg: *DeclGen, w: *Writer, @@ -959,9 +1061,6 @@ pub const DeclGen = struct { const bits = ty.floatBits(target); const f128_val = val.toFloat(f128, zcu); - // All unsigned ints matching float types are pre-allocated. - const repr_ty = pt.intType(.unsigned, bits) catch unreachable; - assert(bits <= 128); var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; var repr_val_big = BigInt.Mutable{ @@ -971,29 +1070,27 @@ pub const DeclGen = struct { }; switch (bits) { + else => unreachable, 16 => repr_val_big.set(@as(u16, @bitCast(val.toFloat(f16, zcu)))), 32 => repr_val_big.set(@as(u32, @bitCast(val.toFloat(f32, zcu)))), 64 => repr_val_big.set(@as(u64, @bitCast(val.toFloat(f64, zcu)))), 80 => repr_val_big.set(@as(u80, @bitCast(val.toFloat(f80, zcu)))), 128 => repr_val_big.set(@as(u128, @bitCast(f128_val))), - else => unreachable, } - var empty = true; if (std.math.isFinite(f128_val)) { try w.writeAll("zig_make_"); try dg.renderTypeForBuiltinFnName(w, ty); try w.writeByte('('); switch (bits) { + else => unreachable, 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}), 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}), 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}), 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}), 128 => try w.print("{x}", .{f128_val}), - else => unreachable, } try w.writeAll(", "); - empty = false; } else { // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan const operation = if (std.math.isNan(f128_val)) @@ -1028,6 +1125,7 @@ pub const DeclGen = struct { try w.writeAll(operation); try w.writeAll(", "); if (std.math.isNan(f128_val)) switch (bits) { + else => unreachable, // We only actually need to pass the significand, but it will get // properly masked anyway, so just pass the whole value. 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}), @@ -1035,16 +1133,23 @@ pub const DeclGen = struct { 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}), 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}), 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}), - else => unreachable, }; try w.writeAll(", "); - empty = false; } - try w.print("{f}", .{try dg.fmtIntLiteralHex( - try pt.intValue_big(repr_ty, repr_val_big.toConst()), - location, - )}); - if (!empty) try w.writeByte(')'); + switch (bits) { + else => unreachable, + 16, 32, 64 => { + // All unsigned ints matching float types are pre-allocated. + const repr_ty = pt.intType(.unsigned, bits) catch unreachable; + try w.print("{f}", .{try dg.fmtIntLiteralHex( + try pt.intValue_big(repr_ty, repr_val_big.toConst()), + location, + )}); + }, + 80 => try F80Repr.write(@bitCast(val.toFloat(f80, zcu)), w, target, location == .static_initializer), + 128 => try F128Repr.write(@bitCast(f128_val), w, target, location == .static_initializer), + } + try w.writeByte(')'); }, .slice => |slice| { if (!location.isInitializer()) { @@ -1319,22 +1424,29 @@ pub const DeclGen = struct { .f128_type, => { const bits = ty.floatBits(target); - // All unsigned ints matching float types are pre-allocated. - const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable; try w.writeAll("zig_make_"); try dg.renderTypeForBuiltinFnName(w, ty); try w.writeByte('('); switch (bits) { - 16 => try w.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}), - 32 => try w.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}), - 64 => try w.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}), - 80 => try w.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}), - 128 => try w.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}), else => unreachable, + 16 => try w.print("{x}", .{undefPattern(f16)}), + 32 => try w.print("{x}", .{undefPattern(f32)}), + 64 => try w.print("{x}", .{undefPattern(f64)}), + 80 => try w.print("{x}", .{undefPattern(f80)}), + 128 => try w.print("{x}", .{undefPattern(f128)}), } try w.writeAll(", "); - try dg.renderUndefValue(w, repr_ty, .other); + switch (bits) { + else => unreachable, + 16, 32, 64 => { + // All unsigned ints matching float types are pre-allocated. + const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable; + try dg.renderUndefValue(w, repr_ty, .other); + }, + 80 => try undefPattern(F80Repr).write(w, target, location == .static_initializer), + 128 => try undefPattern(F128Repr).write(w, target, location == .static_initializer), + } return w.writeByte(')'); }, .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"), @@ -1638,8 +1750,6 @@ pub const DeclGen = struct { try w.writeAll("zig_no_builtin "); } - if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); - // While incomplete types are usually an acceptable substitute for "void", this is not true // in function return types, where "void" is the only incomplete type permitted. const actual_return_type: Type = .fromInterned(fn_info.return_type); @@ -1651,8 +1761,9 @@ pub const DeclGen = struct { const ret_cty: CType = try .lower(effective_return_type, &dg.ctype_deps, dg.arena, zcu); try w.print("{f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); - if (toCallingConvention(fn_info.cc, zcu)) |call_conv| { - try w.print("zig_callconv({s}) ", .{call_conv}); + switch (CType.CallingConvention.fromLang(fn_info.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), } switch (name) { .nav => |nav| try renderNavName(w, nav, ip), @@ -1726,136 +1837,6 @@ pub const DeclGen = struct { try w.print("{f}", .{cty.fmtTypeName(zcu)}); } - const IntCastContext = union(enum) { - c_value: struct { - f: *Function, - value: CValue, - v: Vectorize, - }, - value: struct { - value: Value, - }, - - pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: *Writer, location: ValueRenderLocation) !void { - switch (self.*) { - .c_value => |v| { - try v.f.writeCValue(w, v.value, location); - try v.v.elem(v.f, w); - }, - .value => |v| try dg.renderValue(w, v.value, location), - } - } - }; - fn intCastIsNoop(dg: *DeclGen, dest_ty: Type, src_ty: Type) bool { - const pt = dg.pt; - const zcu = pt.zcu; - const dest_bits = dest_ty.bitSize(zcu); - const dest_int_info = dest_ty.intInfo(pt.zcu); - - const src_is_ptr = src_ty.isPtrAtRuntime(pt.zcu); - const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { - .unsigned => .usize, - .signed => .isize, - } else src_ty; - - const src_bits = src_eff_ty.bitSize(zcu); - const src_int_info = if (src_eff_ty.isAbiInt(pt.zcu)) src_eff_ty.intInfo(pt.zcu) else null; - if (dest_bits <= 64 and src_bits <= 64) { - const needs_cast = src_int_info == null or - (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or - dest_int_info.signedness != src_int_info.?.signedness); - return !needs_cast and !src_is_ptr; - } else return false; - } - /// Renders a cast to an int type, from either an int or a pointer. - /// - /// Some platforms don't have 128 bit integers, so we need to use - /// the zig_make_ and zig_lo_ macros in those cases. - /// - /// | Dest type bits | Src type | Result - /// |------------------|------------------|---------------------------| - /// | < 64 bit integer | pointer | (zig_)(zig_size)src - /// | < 64 bit integer | < 64 bit integer | (zig_)src - /// | < 64 bit integer | > 64 bit integer | zig_lo(src) - /// | > 64 bit integer | pointer | zig_make_(0, (zig_size)src) - /// | > 64 bit integer | < 64 bit integer | zig_make_(0, src) - /// | > 64 bit integer | > 64 bit integer | zig_make_(zig_hi_(src), zig_lo_(src)) - fn renderIntCast( - dg: *DeclGen, - w: *Writer, - dest_ty: Type, - context: IntCastContext, - src_ty: Type, - location: ValueRenderLocation, - ) !void { - const pt = dg.pt; - const zcu = pt.zcu; - const dest_bits = dest_ty.bitSize(zcu); - const dest_int_info = dest_ty.intInfo(zcu); - - const src_is_ptr = src_ty.isPtrAtRuntime(zcu); - const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { - .unsigned => .usize, - .signed => .isize, - } else src_ty; - - const src_bits = src_eff_ty.bitSize(zcu); - const src_int_info = if (src_eff_ty.isAbiInt(zcu)) src_eff_ty.intInfo(zcu) else null; - if (dest_bits <= 64 and src_bits <= 64) { - const needs_cast = src_int_info == null or - (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or - dest_int_info.signedness != src_int_info.?.signedness); - - if (needs_cast) { - try w.writeByte('('); - try dg.renderType(w, dest_ty); - try w.writeByte(')'); - } - if (src_is_ptr) { - try w.writeByte('('); - try dg.renderType(w, src_eff_ty); - try w.writeByte(')'); - } - try context.writeValue(dg, w, location); - } else if (dest_bits <= 64 and src_bits > 64) { - assert(!src_is_ptr); - if (dest_bits < 64) { - try w.writeByte('('); - try dg.renderType(w, dest_ty); - try w.writeByte(')'); - } - try w.writeAll("zig_lo_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeByte(')'); - } else if (dest_bits > 64 and src_bits <= 64) { - try w.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(w, dest_ty); - try w.writeAll("(0, "); - if (src_is_ptr) { - try w.writeByte('('); - try dg.renderType(w, src_eff_ty); - try w.writeByte(')'); - } - try context.writeValue(dg, w, .other); - try w.writeByte(')'); - } else { - assert(!src_is_ptr); - try w.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(w, dest_ty); - try w.writeAll("(zig_hi_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeAll("), zig_lo_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeAll("))"); - } - } - /// Renders to `w` a C declarator whose type is the C lowering of the given Zig type. fn renderTypeAndName( dg: *DeclGen, @@ -2000,6 +1981,7 @@ pub const DeclGen = struct { switch (info) { .none => if (!is_big) return, .bits => {}, + .bits_none, .big_temp_bits => unreachable, } const int_info: std.lang.Type.Int = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{ @@ -2056,6 +2038,72 @@ const CQualifiers = packed struct { restrict: bool = false, }; +pub fn genHeader(zcu: *Zcu, w: *Writer) !void { + const gpa = zcu.comp.gpa; + + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var ctype_deps: CType.Dependencies = .empty; + defer ctype_deps.deinit(gpa); + + const target = zcu.getTarget(); + switch (target.abi) { + .msvc, .itanium => try w.writeAll("#define ZIG_TARGET_ABI_MSVC\n"), + else => {}, + } + for ([_]u16{ 16, 32, 64, 80, 128 }) |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => {}, + .soft => try w.print("#define ZIG_TARGET_SOFT_COMPILER_RT_F{d}_ABI\n", .{bits}), + }; + try w.print( + \\#define ZIG_TARGET_MAX_INT_ALIGNMENT {d} + \\#include "zig.h" + \\ + \\ + , + .{target.cMaxIntAlignment()}, + ); + + var basic_ty: Type = .fromInterned(.first_type); + while (true) : ({ + basic_ty = .fromInterned(@fromBackingInt(@intCast(@backingInt(basic_ty.toIntern()) + 1))); + if (basic_ty.toIntern() == InternPool.Index.last_type) break; + }) { + switch (basic_ty.toIntern()) { + else => {}, + .anyframe_type, + .adhoc_inferred_error_set_type, + .generic_poison_type, + => continue, // skip unsupported types + } + const basic_cty: CType = try .lower(basic_ty, &ctype_deps, arena.allocator(), zcu); + switch (basic_cty) { + .void => {}, // no layout to check + .bool, + .int, + .float, + => try CType.render_defs.writeStaticAssertTypeLayout(basic_ty, basic_cty, w, zcu), + .@"fn", + .@"enum", + .bitpack, + .@"struct", + .union_auto, + .union_extern, + .slice, + .opt, + .arr, + .vec, + .errunion, + .aligned, + .bigint, + .pointer, + .array, + .function, + => {}, + } + } +} + pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void { for (zcu.global_assembly.values()) |asm_source| { try w.print("__asm({f});\n", .{fmtStringLiteral(asm_source, null)}); @@ -2070,16 +2118,16 @@ pub fn genErrDecls( const ip = &zcu.intern_pool; const names = ip.global_error_set.getNamesFromMainThread(); - // Don't generate an invalid empty enum if the global error set is empty! - if (names.len > 0) { - try w.writeAll("enum {\n"); - for (names, 1..) |name_nts, value| { - try w.writeByte(' '); - try renderErrorName(w, name_nts.toSlice(ip)); - try w.print(" = {d}u,\n", .{value}); - } - try w.writeAll("};\n"); + // Don't generate an invalid empty enum/array if the global error set is empty! + if (names.len == 0) return; + + try w.writeAll("enum {\n"); + for (names, 1..) |name_nts, value| { + try w.writeByte(' '); + try renderErrorName(w, name_nts.toSlice(ip)); + try w.print(" = {d}u,\n", .{value}); } + try w.writeAll("};\n"); for (names) |name_nts| { const name = name_nts.toSlice(ip); @@ -2093,7 +2141,7 @@ pub fn genErrDecls( "static {s} const zig_errorName[{d}] = {{", .{ slice_const_u8_sentinel_0_type_name, names.len }, ); - if (names.len > 0) try w.writeByte('\n'); + try w.writeByte('\n'); for (names) |name_nts| { const name = name_nts.toSlice(ip); try w.print( @@ -2114,10 +2162,18 @@ pub fn genTagNameFn( const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); assert(loaded_enum.field_names.len > 0); - if (Type.fromInterned(loaded_enum.int_tag_type).bitSize(zcu) > 64) { - @panic("TODO CBE: tagName for enum over 64 bits"); + switch (CType.classifyInt(enum_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => {}, + .zig_u128, .zig_i128 => @panic("TODO CBE: tagName for 128-bit enums"), + }, + .big => @panic("TODO CBE: tagName for bigint enums"), } + if (!zcu.comp.config.root_strip) try w.print("/* @tagName({f}) */\n", .{ + loaded_enum.name.fmt(ip), + }); try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{ slice_const_u8_sentinel_0_type_name, fmtIdentUnsolo(loaded_enum.name.toSlice(ip)), @@ -2164,6 +2220,7 @@ pub fn genLazyCallModifierFn( const fn_val = zcu.navValue(fn_nav); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.print("static zig_{t} ", .{kind}); try dg.renderFunctionSignature(w, fn_val, .none, .definition, switch (kind) { .never_tail => .{ .nav_never_tail = fn_nav }, @@ -2269,8 +2326,10 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E const gpa = f.dg.gpa; const nav_index = f.dg.owner_nav.unwrap().?; const nav_val = zcu.navValue(nav_index); + const fn_info = zcu.typeToFunc(nav_val.typeOf(zcu)).?; const nav = ip.getNav(nav_index); + if (Type.fromInterned(fn_info.return_type).isNoReturn(zcu)) try fwd_decl_writer.writeAll("zig_noreturn "); try fwd_decl_writer.writeAll("static "); try f.dg.renderFunctionSignature( fwd_decl_writer, @@ -2291,11 +2350,41 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E .{ .nav = nav_index }, ); try header_writer.writeAll(" {\n "); + if (!f.dg.mod.strip) try header_writer.print("/* {f} */\n ", .{nav.fqn.fmt(ip)}); f.free_locals_map.clearRetainingCapacity(); const main_body = f.air.getMainBody(); f.indent(); + if (switch (fn_info.cc) { + inline else => |pl| switch (@TypeOf(pl)) { + void, + std.lang.CallingConvention.SpirvKernelOptions, + std.lang.CallingConvention.SpirvFragmentOptions, + std.lang.CallingConvention.SpirvMeshOptions, + => null, + std.lang.CallingConvention.ArcInterruptOptions, + std.lang.CallingConvention.ArmInterruptOptions, + std.lang.CallingConvention.RiscvInterruptOptions, + std.lang.CallingConvention.ShInterruptOptions, + std.lang.CallingConvention.MicroblazeInterruptOptions, + std.lang.CallingConvention.MipsInterruptOptions, + std.lang.CallingConvention.CommonOptions, + std.lang.CallingConvention.X86RegparmOptions, + => pl.incoming_stack_alignment, + else => @compileError(@tagName(pl)), + }, + }) |incoming_stack_alignment| realign_stack: { + const normal_stack_align = zcu.getTarget().stackAlignment(); + if (incoming_stack_alignment >= normal_stack_align) break :realign_stack; + try header_writer.print("char zig_align({d}) zig_realign_stack;\n ", .{ + normal_stack_align << 1, + }); + try f.code.writer.writeAll( + \\__asm volatile("" :: [zig_realign_stack] "m" (zig_realign_stack)); + ); + try f.newline(); + } try genBodyResolveState(f, undefined, &.{}, main_body, true); try f.outdent(); try f.code.writer.writeByte('}'); @@ -2346,6 +2435,7 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E for (list.keys()) |local_index| { const local = f.locals.items[local_index]; try f.dg.renderTypeAndName(header_writer, local.type, .{ .local = local_index }, .{}, local.alignment); + if (local.array_len != 1) try header_writer.print("[{d}]", .{local.array_len}); try header_writer.writeAll(";\n "); } } @@ -2397,10 +2487,12 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { .@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) { .@"fn" => { + const fn_val: Value = .fromInterned(nav.resolved.?.value); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); try dg.renderFunctionSignature( w, - .fromInterned(nav.resolved.?.value), + fn_val, nav.resolved.?.@"align", .forward_decl, .{ .@"export" = .{ @@ -2461,7 +2553,12 @@ pub fn genDeclValue(dg: *DeclGen, w: *Writer, options: struct { try dg.renderTypeAndName(w, ty, options.name, .{ .@"const" = options.@"const" }, .none); try w.writeAll(" = "); try dg.renderValue(w, options.init_val, .static_initializer); - try w.writeAll(";\n"); + try w.writeByte(';'); + if (dg.owner_nav.unwrap()) |nav_index| { + const ip = &zcu.intern_pool; + if (!dg.mod.strip) try w.print(" /* {f} */", .{ip.getNav(nav_index).fqn.fmt(ip)}); + } + try w.writeByte('\n'); } pub fn genDeclValueFwd(dg: *DeclGen, w: *Writer, options: struct { name: CValue, @@ -2496,11 +2593,13 @@ pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indic const exported_val = exported.getValue(zcu); if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| { const @"export" = export_index.ptr(zcu); + const fn_val = exported.getValue(zcu); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); if (@"export".opts.linkage == .weak) try w.writeAll("zig_weak_linkage_fn "); try dg.renderFunctionSignature( w, - exported.getValue(zcu), + fn_val, exported.getAlign(zcu), .forward_decl, .{ .@"export" = .{ @@ -2662,22 +2761,22 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .mul => try airBinOp(f, inst, "*", "mul", .none), .neg => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "neg", .none), - .div_float => try airBinBuiltinCall(f, inst, "div", .none), + .div_float => try airBinBuiltinCall(f, inst, "div", .big_temp_bits), - .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), + .div_trunc, .div_exact => try airBinOp(f, inst, "/", "divTrunc", .big_temp_bits), .rem => blk: { const bin_op = air_datas[@intFromEnum(inst)].bin_op; const lhs_scalar_ty = f.typeOf(bin_op.lhs).scalarType(zcu); // For binary operations @TypeOf(lhs)==@TypeOf(rhs), // so we only check one. break :blk if (lhs_scalar_ty.isInt(zcu)) - try airBinOp(f, inst, "%", "rem", .none) + try airBinOp(f, inst, "%", "rem", .big_temp_bits) else try airBinBuiltinCall(f, inst, "fmod", .none); }, - .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), - .div_ceil => try airBinBuiltinCall(f, inst, "div_ceil", .none), - .mod => try airBinBuiltinCall(f, inst, "mod", .none), + .div_floor => try airBinBuiltinCall(f, inst, "divFloor", .big_temp_bits), + .div_ceil => try airBinBuiltinCall(f, inst, "divCeil", .big_temp_bits), + .mod => try airBinBuiltinCall(f, inst, "mod", .big_temp_bits), .abs => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "abs", .none), .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits), @@ -2687,7 +2786,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits), .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits), .mul_sat => try airBinBuiltinCall(f, inst, "muls", .bits), - .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits), + .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits_none), .sqrt => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "sqrt", .none), .sin => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "sin", .none), @@ -2764,8 +2863,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .int_from_error => try airNopCast(f, inst), .union_from_enum => try airUnionFromEnum(f, inst), .bit_cast => try airBitCast(f, inst), - .int_cast => try airIntCast(f, inst), - .trunc => try airTrunc(f, inst), + .int_cast => try airIntCast(f, inst, "intCast", .none), + .trunc => try airIntCast(f, inst, "truncate", .bits), .load => try airLoad(f, inst), .store => try airStore(f, inst, false), .store_safe => try airStore(f, inst, true), @@ -2783,9 +2882,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .get_union_tag => try airGetUnionTag(f, inst), .clz => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "clz", .bits), .ctz => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "ctz", .bits), - .popcount => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "popcount", .bits), - .byte_swap => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "byte_swap", .bits), - .bit_reverse => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "bit_reverse", .bits), + .popcount => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "popCount", .bits), + .byte_swap => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "byteSwap", .bits), + .bit_reverse => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "bitReverse", .bits), .tag_name => try airTagName(f, inst), .error_name => try airErrorName(f, inst), .splat => try airSplat(f, inst), @@ -3124,7 +3223,16 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { const zcu = pt.zcu; const inst_ty = f.typeOfIndex(inst); const elem_ty = inst_ty.childType(zcu); - if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty }; + if (!elem_ty.hasRuntimeBits(zcu)) { + const w = &f.code.writer; + const local = try f.allocLocal(inst, inst_ty); + try f.writeCValue(w, local, .other); + try w.writeAll(" = "); + try f.dg.renderOpvPointer(w, inst_ty, .other); + try w.writeByte(';'); + try f.newline(); + return local; + } const local = try f.allocLocalValue(.{ .type = elem_ty, @@ -3298,120 +3406,57 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { } } -fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { +fn airIntCast(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { const pt = f.dg.pt; const zcu = pt.zcu; const ty_op = f.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try f.resolveInst(ty_op.operand); - try reap(f, inst, &.{ty_op.operand}); - - const inst_ty = f.typeOfIndex(inst); + const inst_ty = ty_op.ty.toType(); const inst_scalar_ty = inst_ty.scalarType(zcu); const operand_ty = f.typeOf(ty_op.operand); - const scalar_ty = operand_ty.scalarType(zcu); - - // `intCastIsNoop` doesn't apply to vectors because every vector lowers to a different C struct. - if (inst_ty.zigTypeTag(zcu) != .vector and f.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) { - return f.moveCValue(inst, inst_ty, operand); - } - - const w = &f.code.writer; - const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); - try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .other); - try w.writeByte(';'); - try f.newline(); - try v.end(f, inst, w); - return local; -} - -fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { - const pt = f.dg.pt; - const zcu = pt.zcu; - const ty_op = f.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const operand_scalar_ty = operand_ty.scalarType(zcu); + const is_big = lowersToBigInt(operand_ty, zcu); const operand = try f.resolveInst(ty_op.operand); - try reap(f, inst, &.{ty_op.operand}); - - const inst_ty = f.typeOfIndex(inst); - const inst_scalar_ty = inst_ty.scalarType(zcu); - const dest_int_info = inst_scalar_ty.intInfo(zcu); - const dest_bits = dest_int_info.bits; - const dest_c_bits = toCIntBits(dest_bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - const operand_ty = f.typeOf(ty_op.operand); - const scalar_ty = operand_ty.scalarType(zcu); - const scalar_int_info = scalar_ty.intInfo(zcu); + if (!is_big) try reap(f, inst, &.{ty_op.operand}); - const need_cast = dest_c_bits < 64; - const need_lo = scalar_int_info.bits > 64 and dest_bits <= 64; - const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits); - if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand); + const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); + const ref_arg = lowersToBigInt(operand_scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); + if (is_big) try reap(f, inst, &.{ty_op.operand}); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); - if (need_cast) { - try w.writeByte('('); - try f.renderType(w, inst_scalar_ty); - try w.writeByte(')'); - } - if (need_lo) { - try w.writeAll("zig_lo_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - try w.writeByte('('); + if (!ref_ret) { + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(" = "); } - if (!need_mask) { - try f.writeCValue(w, operand, .other); + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.print("_{s}_", .{operation}); + try f.dg.renderTypeForBuiltinFnName(w, operand_scalar_ty); + try w.writeByte('('); + if (ref_ret) { + try w.writeByte('&'); + try f.writeCValue(w, local, .other); try v.elem(f, w); - } else switch (dest_int_info.signedness) { - .unsigned => { - try w.writeAll("zig_and_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - try w.writeByte('('); - try f.writeCValue(w, operand, .other); - try v.elem(f, w); - try w.print(", {f})", .{ - try f.fmtIntLiteralHex(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)), - }); - }, - .signed => { - const c_bits = toCIntBits(scalar_int_info.bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - const shift_val = try pt.intValue(.u8, c_bits - dest_bits); - - try w.writeAll("zig_shr_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - if (c_bits == 128) { - try w.print("(zig_bitCast_i{d}(", .{c_bits}); - } else { - try w.print("((int{d}_t)", .{c_bits}); - } - try w.print("zig_shl_u{d}(", .{c_bits}); - if (c_bits == 128) { - try w.print("zig_bitCast_u{d}(", .{c_bits}); - } else { - try w.print("(uint{d}_t)", .{c_bits}); - } - try f.writeCValue(w, operand, .other); - try v.elem(f, w); - if (c_bits == 128) try w.writeByte(')'); - try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); - if (c_bits == 128) try w.writeByte(')'); - try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); - }, + try w.writeAll(", "); } - if (need_lo) try w.writeByte(')'); - try w.writeByte(';'); + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, inst_scalar_ty, info); + try f.dg.renderBuiltinInfo(w, operand_scalar_ty, .none); + try w.writeAll(");"); try f.newline(); try v.end(f, inst, w); + return local; } @@ -3525,39 +3570,46 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: const ty_pl = f.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; + const lhs_ty = f.typeOf(bin_op.lhs); + const rhs_ty = f.typeOf(bin_op.rhs); + const is_big = lowersToBigInt(lhs_ty, zcu); + const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); - try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const inst_ty = f.typeOfIndex(inst); - const operand_ty = f.typeOf(bin_op.lhs); - const scalar_ty = operand_ty.scalarType(zcu); + const lhs_scalar_ty = lhs_ty.scalarType(zcu); + const rhs_scalar_ty = rhs_ty.scalarType(zcu); - const ref_arg = lowersToBigInt(scalar_ty, zcu); + const ref_lhs = lowersToBigInt(lhs_scalar_ty, zcu); + const ref_rhs = lowersToBigInt(rhs_scalar_ty, zcu); const w = &f.code.writer; - const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, w, operand_ty); + const local = try f.allocLocal(inst, f.typeOfIndex(inst)); + if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + const v = try Vectorize.start(f, inst, w, lhs_ty); try f.writeCValueMember(w, local, .{ .field = 1 }); try v.elem(f, w); - try w.writeAll(" = zig_"); + try w.writeAll(" = "); + try w.writeAll("zig_"); try w.writeAll(operation); try w.writeAll("o_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try f.dg.renderTypeForBuiltinFnName(w, lhs_scalar_ty); try w.writeByte('('); // '&dest', possibly preceded by a cast - switch (zcu.intern_pool.indexToKey(scalar_ty.toIntern())) { + switch (zcu.intern_pool.indexToKey(lhs_scalar_ty.toIntern())) { .int_type => {}, // we already have a '[u]intX_t *' .simple_type => { // '&dest' will be something like a 'uintptr_t *', which might be a different C type to // the equivalent sized integer (e.g. 'uint64_t *'), so we need a cast. We don't need a // cast on the *operands* because they are passed by value (except for big integers, // where this issue doesn't exist because no "simple" int type needs bigint repr). - try w.print("({s}int{d}_t *)", .{ - if (scalar_ty.isUnsignedInt(zcu)) "u" else "", - scalar_ty.abiSize(zcu) * 8, - }); + const inst_int_info = lhs_scalar_ty.intInfo(zcu); + try w.print("({s}int{d}_t *)", .{ switch (inst_int_info.signedness) { + .signed => "", + .unsigned => "u", + }, inst_int_info.bits }); }, else => unreachable, } @@ -3566,14 +3618,24 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_lhs) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); - if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, scalar_ty, info); + if (ref_rhs) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, lhs_scalar_ty, info); try w.writeAll(");"); try f.newline(); try v.end(f, inst, w); @@ -3622,8 +3684,18 @@ fn airBinOp( const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; const operand_ty = f.typeOf(bin_op.lhs); const scalar_ty = operand_ty.scalarType(zcu); - if ((scalar_ty.isInt(zcu) and scalar_ty.bitSize(zcu) > 64) or scalar_ty.isRuntimeFloat()) - return try airBinBuiltinCall(f, inst, operation, info); + + builtin: { + if (scalar_ty.isInt(zcu)) switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } else if (!scalar_ty.isRuntimeFloat()) break :builtin; + return airBinBuiltinCall(f, inst, operation, info); + } const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3662,19 +3734,21 @@ fn airCmpOp( const lhs_ty = f.typeOf(data.lhs); const scalar_ty = lhs_ty.scalarType(zcu); - if (scalar_ty.isInt(zcu)) { - const scalar_bits = scalar_ty.bitSize(zcu); - if (scalar_bits > 64) return airCmpBuiltinCall( - f, - inst, - data, - operator, - .cmp, - if (scalar_bits > 128) .bits else .none, - ); + builtin: { + if (scalar_ty.isInt(zcu)) { + switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } + return airCmpBuiltinCall(f, inst, data, operator, .cmp, .none); + } + if (scalar_ty.isRuntimeFloat()) + return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); } - if (scalar_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); const inst_ty = f.typeOfIndex(inst); const lhs = try f.resolveInst(data.lhs); @@ -3716,21 +3790,23 @@ fn airEquality( const pt = f.dg.pt; const zcu = pt.zcu; const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; - const operand_ty = f.typeOf(bin_op.lhs); - if (operand_ty.isAbiInt(zcu)) { - const operand_bits = operand_ty.bitSize(zcu); - if (operand_bits > 64) return airCmpBuiltinCall( - f, - inst, - bin_op, - operator, - .cmp, - if (operand_bits > 128) .bits else .none, - ); + + builtin: { + if (operand_ty.isAbiInt(zcu)) { + switch (CType.classifyInt(operand_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } + return airCmpBuiltinCall(f, inst, bin_op, operator, .cmp, .none); + } + if (operand_ty.isRuntimeFloat()) + return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); } - if (operand_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3809,7 +3885,7 @@ fn airCmpLteErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(w, local, .other); try w.writeAll(" = "); try f.writeCValue(w, operand, .other); - try w.writeAll(" < sizeof(zig_errorName) / sizeof(*zig_errorName);"); + try w.writeAll(" <= sizeof(zig_errorName) / sizeof(*zig_errorName);"); try f.newline(); return local; } @@ -3862,8 +3938,17 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - if ((inst_scalar_ty.isInt(zcu) and inst_scalar_ty.bitSize(zcu) > 64) or inst_scalar_ty.isRuntimeFloat()) - return try airBinBuiltinCall(f, inst, operation, .none); + builtin: { + if (inst_scalar_ty.isInt(zcu)) switch (CType.classifyInt(inst_scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } else if (!inst_scalar_ty.isRuntimeFloat()) break :builtin; + return airBinBuiltinCall(f, inst, operation, .none); + } const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3979,10 +4064,7 @@ fn airCall( try w.writeAll("(void)"); break :result .none; } else { - const local = try f.allocAlignedLocal(inst, .{ - .type = ret_ty, - .alignment = .none, - }); + const local = try f.allocAlignedLocal(inst, .{ .type = ret_ty }); try f.writeCValue(w, local, .other); try w.writeAll(" = "); break :result local; @@ -4058,16 +4140,7 @@ fn airCall( fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { const dbg_stmt = f.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt; const w = &f.code.writer; - // TODO re-evaluate whether to emit these or not. If we naively emit - // these directives, the output file will report bogus line numbers because - // every newline after the #line directive adds one to the line. - // We also don't print the filename yet, so the output is strictly unhelpful. - // If we wanted to go this route, we would need to go all the way and not output - // newlines until the next dbg_stmt occurs. - // Perhaps an additional compilation option is in order? - //try w.print("#line {d}", .{dbg_stmt.line + 1}); - //try f.newline(); - try w.print("/* file:{d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); + try w.print("/* {d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); try f.newline(); return .none; } @@ -4433,12 +4506,12 @@ fn airBitCast(f: *Function, inst: Air.Inst.Index) Error!CValue { const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_scalar_ty = dest_ty.scalarType(zcu); - // Some cases are handled with a simple cast: - // * float -> float - // * bool -> int if ((operand_scalar_ty.isRuntimeFloat() and dest_scalar_ty.isRuntimeFloat()) or (operand_scalar_ty.toIntern() == .bool_type and dest_scalar_ty.isAbiInt(zcu))) { + // Some cases are handled with a simple cast: + // * float -> float + // * bool -> int try f.writeCValue(w, dest_local, .other); try v.elem(f, w); try w.writeAll(" = ("); @@ -4458,85 +4531,44 @@ fn airBitCast(f: *Function, inst: Air.Inst.Index) Error!CValue { try v.elem(f, w); try w.writeAll(" != 0;"); try f.newline(); - } else if (dest_scalar_ty.isRuntimeFloat()) { - // For int->float, just do a memcpy. - assert(operand_scalar_ty.isAbiInt(zcu)); - try w.writeAll("memcpy(&"); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(", &"); - switch (operand) { - .constant => |val| try f.dg.renderValueAsLvalue(w, val), - else => try f.writeCValue(w, operand, .other), - } - try v.elem(f, w); - try w.print(", {d});", .{@min(operand_scalar_ty.abiSize(zcu), dest_scalar_ty.abiSize(zcu))}); - try f.newline(); } else { - // The only remaining possibility is that the result is an integer. We will need to use - // `zig_wrap_*` to correct the "padding" bits after we populate the value bits. - assert(dest_scalar_ty.isAbiInt(zcu)); assert(operand_scalar_ty.isRuntimeFloat() or operand_scalar_ty.isAbiInt(zcu)); + assert(dest_scalar_ty.isRuntimeFloat() or dest_scalar_ty.isAbiInt(zcu)); - // memcpy the value... - try w.writeAll("memcpy(&"); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(", &"); - switch (operand) { - .constant => |val| try f.dg.renderValueAsLvalue(w, val), - else => try f.writeCValue(w, operand, .other), + const ref_ret = lowersToBigInt(dest_scalar_ty, zcu); + const ref_arg = lowersToBigInt(operand_scalar_ty, zcu); + + if (!ref_ret) { + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(" = "); + } + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, dest_scalar_ty); + try w.writeAll("_bitCast_"); + try f.dg.renderTypeForBuiltinFnName(w, operand_scalar_ty); + try w.writeByte('('); + if (ref_ret) { + try w.writeByte('&'); + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(", "); } + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); - try w.print(", {d});", .{@min(operand_scalar_ty.abiSize(zcu), dest_scalar_ty.abiSize(zcu))}); + try f.dg.renderBuiltinInfo( + w, + dest_scalar_ty, + if (operand_scalar_ty.isRuntimeFloat() or dest_scalar_ty.isRuntimeFloat()) .none else .bits, + ); + try w.writeAll(");"); try f.newline(); - - // ...and ensure padding bits have the correct value. - switch (CType.classifyInt(dest_scalar_ty, zcu)) { - .void => unreachable, // opv - .small => { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(" = zig_wrap_"); - try f.dg.renderTypeForBuiltinFnName(w, dest_scalar_ty); - try w.writeByte('('); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, dest_scalar_ty, .bits); - try w.writeAll(");"); - try f.newline(); - }, - .big => |big| { - const dest_info = dest_scalar_ty.intInfo(zcu); - const padding_index: u16 = switch (f.dg.mod.resolved_target.result.cpu.arch.endian()) { - .little => big.limbs_len - 1, - .big => 0, - }; - const wrap_bits = ((dest_info.bits - 1) % big.limb_size.bits()) + 1; - if (big.limb_size != .@"128" or dest_info.signedness == .unsigned) { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}] = zig_wrap_{c}{d}(", .{ - padding_index, - signAbbrev(dest_info.signedness), - big.limb_size.bits(), - }); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}], {d});", .{ padding_index, wrap_bits }); - } else { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}] = zig_bitCast_u128(zig_wrap_i128(zig_bitCast_i128(", .{ - padding_index, - }); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}]), {d}));", .{ padding_index, wrap_bits }); - try f.newline(); - } - }, - } } try v.end(f, inst, w); @@ -4906,11 +4938,9 @@ fn lowerSwitchCmp( fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool { const dg = f.dg; - const target = &dg.mod.resolved_target.result; return switch (constraint[0]) { '{' => true, - 'i', 'r' => false, - 'I' => !target.cpu.arch.isArm(), + 'r', 'i', 'n', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P' => false, else => switch (value) { .constant => |val| switch (dg.pt.zcu.intern_pool.indexToKey(val.toIntern())) { .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { @@ -4937,10 +4967,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const w = &f.code.writer; const inst_ty = f.typeOfIndex(inst); const inst_local = if (inst_ty.hasRuntimeBits(zcu)) local: { - const inst_local = try f.allocLocalValue(.{ - .type = inst_ty, - .alignment = .none, - }); + const inst_local = try f.allocLocalValue(.{ .type = inst_ty }); if (f.wantSafety()) { try f.writeCValue(w, inst_local, .other); try w.writeAll(" = "); @@ -4967,10 +4994,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (is_reg) { const output_ty = if (output.operand == .none) inst_ty else f.typeOf(output.operand).childType(zcu); try w.writeAll("register "); - const output_local = try f.allocLocalValue(.{ - .type = output_ty, - .alignment = .none, - }); + const output_local = try f.allocLocalValue(.{ .type = output_ty }); try f.allocs.put(gpa, output_local.new_local, false); try f.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none); try w.writeAll(" __asm(\""); @@ -5000,10 +5024,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (asmInputNeedsLocal(f, constraint, input_val)) { const input_ty = f.typeOf(input.operand); if (is_reg) try w.writeAll("register "); - const input_local = try f.allocLocalValue(.{ - .type = input_ty, - .alignment = .none, - }); + const input_local = try f.allocLocalValue(.{ .type = input_ty }); try f.allocs.put(gpa, input_local.new_local, false); // Do not render the declaration as `const` qualified if we're generating an // explicit `register` local, as GCC will ignore the constraint completely. @@ -5853,28 +5874,124 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { else unreachable; + const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); + const ref_operand = lowersToBigInt(scalar_ty, zcu); + const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.print("_intCast_{c}{d}", .{ + @as(u8, switch (inst_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(inst_int_info.bits, 32)), + }); + try w.writeAll("(&"); + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(", "); + } + } else { + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(" = "); + } if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try w.writeAll("zig_wrap_"); - try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); - try w.writeByte('('); + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) try w.print("zig_{c}{d}_truncate_{[0]c}{[1]d}(", .{ + @as(u8, switch (inst_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(inst_int_info.bits, 32)), + }); } try w.writeAll("zig_"); try w.writeAll(operation); try w.writeAll(compilerRtAbbrev(scalar_ty, zcu, target)); try w.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target)); try w.writeByte('('); - try f.writeCValue(w, operand, .other); - try v.elem(f, w); + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits > 128) { + try w.writeByte('&'); + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(", "); + } + } + if (ref_operand) { + const operand_int_info = scalar_ty.intInfo(zcu); + if (operand_int_info.bits <= 128) { + try w.print("zig_{c}{d}_intCast_", .{ + @as(u8, switch (operand_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(operand_int_info.bits, 32)), + }); + try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeAll("(&"); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, scalar_ty, .none); + try w.writeByte(')'); + } else { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + try v.elem(f, w); + try w.print(", {f}", .{fmtUnsignedIntLiteralSmall( + target, + .uint16_t, + operand_int_info.bits, + false, + 10, + .lower, + )}); + } + } else { + try f.writeCValue(w, operand, .other); + try v.elem(f, w); + } + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits > 128) try w.print(", {f}", .{fmtUnsignedIntLiteralSmall( + target, + .uint16_t, + inst_int_info.bits, + false, + 10, + .lower, + )}); + } try w.writeByte(')'); if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try f.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits); - try w.writeByte(')'); + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try w.print(", {f}", .{ + try f.dg.fmtIntLiteralDec(try pt.intValue(.u8, inst_int_info.bits), .other), + }); + try w.writeByte(')'); + } + } + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try f.dg.renderBuiltinInfo(w, inst_scalar_ty, .none); + try w.writeByte(')'); + } } try w.writeByte(';'); try f.newline(); @@ -5893,18 +6010,21 @@ fn airUnBuiltinCall( const pt = f.dg.pt; const zcu = pt.zcu; - const operand = try f.resolveInst(operand_ref); - try reap(f, inst, &.{operand_ref}); const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); const operand_ty = f.typeOf(operand_ref); const scalar_ty = operand_ty.scalarType(zcu); + const is_big = lowersToBigInt(operand_ty, zcu); + + const operand = try f.resolveInst(operand_ref); + if (!is_big) try reap(f, inst, &.{operand_ref}); const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); const ref_arg = lowersToBigInt(scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); + if (is_big) try reap(f, inst, &.{operand_ref}); const v = try Vectorize.start(f, inst, w, operand_ty); if (!ref_ret) { try f.writeCValue(w, local, .other); @@ -5920,8 +6040,13 @@ fn airUnBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, operand, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, info); try w.writeAll(");"); @@ -5941,8 +6066,9 @@ fn airBinBuiltinCall( const zcu = pt.zcu; const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; - const operand_ty = f.typeOf(bin_op.lhs); - const is_big = lowersToBigInt(operand_ty, zcu); + const lhs_ty = f.typeOf(bin_op.lhs); + const rhs_ty = f.typeOf(bin_op.rhs); + const is_big = lowersToBigInt(lhs_ty, zcu); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -5950,22 +6076,31 @@ fn airBinBuiltinCall( const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - const scalar_ty = operand_ty.scalarType(zcu); + const lhs_scalar_ty = lhs_ty.scalarType(zcu); + const rhs_scalar_ty = rhs_ty.scalarType(zcu); const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); - const ref_arg = lowersToBigInt(scalar_ty, zcu); + const ref_lhs = lowersToBigInt(lhs_scalar_ty, zcu); + const ref_rhs = lowersToBigInt(rhs_scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const v = try Vectorize.start(f, inst, w, operand_ty); + const v = try Vectorize.start(f, inst, w, lhs_ty); if (!ref_ret) { try f.writeCValue(w, local, .other); try v.elem(f, w); try w.writeAll(" = "); } try w.print("zig_{s}_", .{operation}); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try f.dg.renderTypeForBuiltinFnName(w, lhs_scalar_ty); + switch (info) { + .bits, .none, .big_temp_bits => {}, + .bits_none => { + try w.writeByte('_'); + try f.dg.renderTypeForBuiltinFnName(w, rhs_scalar_ty); + }, + } try w.writeByte('('); if (ref_ret) { try w.writeByte('&'); @@ -5973,15 +6108,45 @@ fn airBinBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_lhs) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); - if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, scalar_ty, info); - try w.writeAll(");\n"); + if (ref_rhs) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, lhs_scalar_ty, info: switch (info) { + .none => .none, + .bits, .bits_none => .bits, + .big_temp_bits => { + if (lowersToBigInt(lhs_scalar_ty, zcu)) { + const temp_local = try f.allocAlignedLocal(inst, .{ + .type = lhs_scalar_ty, + .array_len = 2, + }); + try w.writeAll(", &"); + try f.writeCValue(w, temp_local, .other); + try freeLocal(f, inst, temp_local.new_local, null); + } + break :info .none; + }, + }); + switch (info) { + .none, .bits, .big_temp_bits => {}, + .bits_none => try f.dg.renderBuiltinInfo(w, rhs_scalar_ty, .none), + } + try w.writeAll(");"); + try f.newline(); try v.end(f, inst, w); return local; @@ -6029,12 +6194,22 @@ fn airCmpBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, info); try w.writeByte(')'); @@ -6595,7 +6770,8 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue { }, .value => |val| try f.dg.renderValue(w, .fromInterned(val), .other), } - try w.writeAll(";\n"); + try w.writeByte(';'); + try f.newline(); } return local; @@ -6653,7 +6829,14 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { const operand_ty = f.typeOf(reduce.operand); const w = &f.code.writer; - const use_operator = scalar_ty.bitSize(zcu) <= 64; + const use_operator, const is_big = if (scalar_ty.isInt(zcu)) switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => .{ true, false }, + .zig_u128, .zig_i128 => .{ false, false }, + }, + .big => .{ false, true }, + } else .{ false, false }; const op: union(enum) { const Func = struct { operation: []const u8, info: BuiltinInfo = .none }; builtin: Func, @@ -6742,25 +6925,57 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { try f.newline(); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, accum, .other); switch (op) { .builtin => |func| { - try w.print(" = zig_{s}_", .{func.operation}); + const prev_accum = if (is_big) prev_accum: { + const prev_accum = try f.allocLocal(inst, scalar_ty); + try f.writeCValue(w, prev_accum, .other); + try w.writeAll(" = "); + try f.writeCValue(w, accum, .other); + try w.writeByte(';'); + try f.newline(); + break :prev_accum prev_accum; + } else prev_accum: { + try f.writeCValue(w, accum, .other); + try w.writeAll(" = "); + break :prev_accum accum; + }; + try w.print("zig_{s}_", .{func.operation}); try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); try w.writeByte('('); - try f.writeCValue(w, accum, .other); + if (is_big) { + try w.writeByte('&'); + switch (accum) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, accum, .other), + } + try w.writeAll(", &"); + switch (prev_accum) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, prev_accum, .other), + } + } else try f.writeCValue(w, prev_accum, .other); try w.writeAll(", "); - try f.writeCValue(w, operand, .other); + if (is_big) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, func.info); try w.writeByte(')'); + if (is_big) try freeLocal(f, inst, prev_accum.new_local, null); }, .infix => |ass| { + try f.writeCValue(w, accum, .other); try w.writeAll(ass); try f.writeCValue(w, operand, .other); try v.elem(f, w); }, .ternary => |cmp| { + try f.writeCValue(w, accum, .other); try w.writeAll(" = "); try f.writeCValue(w, accum, .other); try w.writeAll(cmp); @@ -7097,101 +7312,6 @@ fn writeMemoryOrder(w: *Writer, order: std.lang.AtomicOrder) !void { return w.writeAll(toMemoryOrder(order)); } -fn toCallingConvention(cc: std.lang.CallingConvention, zcu: *Zcu) ?[]const u8 { - if (zcu.getTarget().cCallingConvention()) |ccc| { - if (cc.eql(ccc)) { - return null; - } - } - return switch (cc) { - .auto, .naked => null, - - .x86_16_cdecl => "cdecl", - .x86_16_regparmcall => "regparmcall", - .x86_64_sysv, .x86_sysv => "sysv_abi", - .x86_64_win, .x86_win => "ms_abi", - .x86_16_stdcall, .x86_stdcall => "stdcall", - .x86_fastcall => "fastcall", - .x86_thiscall => "thiscall", - - .x86_vectorcall, - .x86_64_vectorcall, - => "vectorcall", - - .x86_64_regcall_v3_sysv, - .x86_64_regcall_v4_win, - .x86_regcall_v3, - .x86_regcall_v4_win, - => "regcall", - - .aarch64_vfabi => "aarch64_vector_pcs", - .aarch64_vfabi_sve => "aarch64_sve_pcs", - - .arm_aapcs => "pcs(\"aapcs\")", - .arm_aapcs_vfp => "pcs(\"aapcs-vfp\")", - - .arc_interrupt => |opts| switch (opts.type) { - inline else => |t| "interrupt(\"" ++ @tagName(t) ++ "\")", - }, - - .arm_interrupt => |opts| switch (opts.type) { - .generic => "interrupt", - .irq => "interrupt(\"IRQ\")", - .fiq => "interrupt(\"FIQ\")", - .swi => "interrupt(\"SWI\")", - .abort => "interrupt(\"ABORT\")", - .undef => "interrupt(\"UNDEF\")", - }, - - .avr_signal => "signal", - - .microblaze_interrupt => |opts| switch (opts.type) { - .user => "save_volatiles", - .regular => "interrupt_handler", - .fast => "fast_interrupt", - .breakpoint => "break_handler", - }, - - .mips_interrupt, - .mips64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .riscv64_lp64_v, .riscv32_ilp32_v => "riscv_vector_cc", - - .riscv32_interrupt, - .riscv64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .sh_renesas => "renesas", - .sh_interrupt => |opts| switch (opts.save) { - .fpscr => "trapa_handler", // Implies `interrupt_handler`. - .high => "interrupt_handler, nosave_low_regs", - .full => "interrupt_handler", - .bank => "interrupt_handler, resbank", - }, - - .m68k_rtd => "m68k_rtd", - - .avr_interrupt, - .csky_interrupt, - .m68k_interrupt, - .msp430_interrupt, - .x86_16_interrupt, - .x86_interrupt, - .x86_64_interrupt, - => "interrupt", - - .ez80_tiflags, - => "__tiflags__", - - else => unreachable, // `Zcu.callconvSupported` - }; -} - fn toAtomicRmwSuffix(order: std.lang.AtomicRmwOp) []const u8 { return switch (order) { .Xchg => "xchg", @@ -7224,17 +7344,18 @@ fn signAbbrev(signedness: std.lang.Signedness) u8 { fn compilerRtAbbrev(ty: Type, zcu: *Zcu, target: *const std.Target) []const u8 { return if (ty.isInt(zcu)) switch (ty.intInfo(zcu).bits) { + 0 => unreachable, 1...32 => "si", 33...64 => "di", 65...128 => "ti", - else => unreachable, + else => "ei", } else if (ty.isRuntimeFloat()) switch (ty.floatBits(target)) { + else => unreachable, 16 => "hf", 32 => "sf", 64 => "df", 80 => "xf", - 128 => "tf", - else => unreachable, + 128 => if (target.cpu.arch.isPowerPC()) "kf" else "tf", } else unreachable; } @@ -7390,10 +7511,8 @@ fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Alt(FormatStringCont return .{ .data = .{ .str = str, .sentinel = sentinel } }; } -fn undefPattern(comptime IntType: type) IntType { - const int_info = @typeInfo(IntType).int; - const UnsignedType = @Int(.unsigned, int_info.bits); - return @bitCast(@as(UnsignedType, (1 << (int_info.bits | 1)) / 3)); +fn undefPattern(comptime Result: type) Result { + return @bitCast(@as(@Int(.unsigned, @bitSizeOf(Result)), (1 << (@bitSizeOf(Result) | 1)) / 3)); } const FormatIntLiteralContext = struct { @@ -7580,11 +7699,9 @@ const FormatSignedIntLiteralSmall = struct { case: std.fmt.Case, pub fn format(data: FormatSignedIntLiteralSmall, w: *Writer) Writer.Error!void { const bits = data.int_cty.bits(data.target); - const max_int: i64 = @bitCast((@as(u64, 1) << @intCast(bits - 1)) - 1); - const min_int: i64 = @bitCast(@as(u64, 1) << @intCast(bits - 1)); - if (data.val == max_int) { + if (data.val == @as(i64, std.math.maxInt(i64)) >> @intCast(64 - bits)) { return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)}); - } else if (data.val == min_int) { + } else if (data.val == @as(i64, std.math.minInt(i64)) >> @intCast(64 - bits)) { return w.print("{s}_MIN", .{minMaxMacroPrefix(data.int_cty)}); } if (data.val < 0) try w.writeByte('-'); @@ -7596,7 +7713,7 @@ const FormatSignedIntLiteralSmall = struct { 16 => try w.writeAll("0x"), else => unreachable, } - // This `@abs` is safe thanks to the `min_int` case above. + // This `@abs` is safe thanks to the min int check above. try w.printInt(@abs(data.val), data.base, data.case, .{}); try w.writeAll(intLiteralSuffix(data.int_cty)); } @@ -7610,8 +7727,7 @@ const FormatUnsignedIntLiteralSmall = struct { case: std.fmt.Case, pub fn format(data: FormatUnsignedIntLiteralSmall, w: *Writer) Writer.Error!void { const bits = data.int_cty.bits(data.target); - const max_int: u64 = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits); - if (data.val == max_int) { + if (data.val == @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)) { return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)}); } try w.writeAll(intLiteralPrefix(data.int_cty, data.is_global)); @@ -7735,6 +7851,31 @@ fn intLiteralSuffix(cty: CType.Int) []const u8 { }; } +const F80Repr = packed struct { + mantissa: u64, + exponent: u16, + + fn write(repr: F80Repr, w: *Writer, target: *const std.Target, is_global: bool) Writer.Error!void { + try w.print("zig_{s}_repr_f80({f}, {f})", .{ + if (is_global) "init" else "make", + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.mantissa, is_global, 16, .lower), + fmtUnsignedIntLiteralSmall(target, .uint16_t, repr.exponent, is_global, 16, .lower), + }); + } +}; +const F128Repr = packed struct { + lo: u64, + hi: u64, + + fn write(repr: F128Repr, w: *Writer, target: *const std.Target, is_global: bool) Writer.Error!void { + try w.print("zig_{s}_repr_f128({f}, {f})", .{ + if (is_global) "init" else "make", + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.hi, is_global, 16, .lower), + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.lo, is_global, 16, .lower), + }); + } +}; + const Materialize = struct { local: CValue, diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index 8e86c0da93dabcda0bdfec08c406bbe0dab4f04d..347dc7e16e27dce1c3dd41b006f860f5772fce6c 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -44,8 +44,175 @@ pub const CType = union(enum) { param_tys: []const CType, ret_ty: *const CType, varargs: bool, + cc: CallingConvention, }, + pub const CallingConvention = enum { + c, + + cdecl, + regparmcall, + sysv_abi, + ms_abi, + stdcall, + fastcall, + thiscall, + + vectorcall, + + regcall, + + aarch64_vector_pcs, + aarch64_sve_pcs, + + @"pcs(\"aapcs\")", + @"pcs(\"aapcs-vfp\")", + + @"interrupt(\"ilink1\")", + @"interrupt(\"ilink2\")", + @"interrupt(\"ilink\")", + @"interrupt(\"firq\")", + + interrupt, + @"interrupt(\"IRQ\")", + @"interrupt(\"FIQ\")", + @"interrupt(\"SWI\")", + @"interrupt(\"ABORT\")", + @"interrupt(\"UNDEF\")", + + signal, + + save_volatiles, + interrupt_handler, + fast_interrupt, + break_handler, + + @"interrupt(\"eic\")", + @"interrupt(\"sw0\")", + @"interrupt(\"sw1\")", + @"interrupt(\"hw0\")", + @"interrupt(\"hw1\")", + @"interrupt(\"hw2\")", + @"interrupt(\"hw3\")", + @"interrupt(\"hw4\")", + @"interrupt(\"hw5\")", + + riscv_vector_cc, + @"interrupt(\"supervisor\")", + @"interrupt(\"machine\")", + + renesas, + /// Implies `interrupt_handler`. + trapa_handler, + @"interrupt_handler, nosave_low_regs", + @"interrupt_handler, resbank", + + m68k_rtd, + + tiflags, + + pub fn fromLang(cc: std.lang.CallingConvention, target: *const std.Target) CallingConvention { + if (target.cCallingConvention()) |ccc| { + if (cc.eql(ccc)) { + return .c; + } + } + return switch (cc) { + .auto, .naked => .c, + + .x86_16_cdecl => .cdecl, + .x86_16_regparmcall => .regparmcall, + .x86_64_sysv, .x86_sysv => .sysv_abi, + .x86_64_win, .x86_win, .x86_mingw => .ms_abi, + .x86_16_stdcall, .x86_stdcall => .stdcall, + .x86_fastcall => .fastcall, + .x86_thiscall => .thiscall, + + .x86_vectorcall, + .x86_64_vectorcall, + => .vectorcall, + + .x86_64_regcall_v3_sysv, + .x86_64_regcall_v4_win, + .x86_regcall_v3, + .x86_regcall_v4_win, + => .regcall, + + .aarch64_vfabi => .aarch64_vector_pcs, + .aarch64_vfabi_sve => .aarch64_sve_pcs, + + .arm_aapcs => .@"pcs(\"aapcs\")", + .arm_aapcs_vfp => .@"pcs(\"aapcs-vfp\")", + + .arc_interrupt => |opts| switch (opts.type) { + .ilink1 => .@"interrupt(\"ilink1\")", + .ilink2 => .@"interrupt(\"ilink2\")", + .ilink => .@"interrupt(\"ilink\")", + .firq => .@"interrupt(\"firq\")", + }, + + .arm_interrupt => |opts| switch (opts.type) { + .generic => .interrupt, + .irq => .@"interrupt(\"IRQ\")", + .fiq => .@"interrupt(\"FIQ\")", + .swi => .@"interrupt(\"SWI\")", + .abort => .@"interrupt(\"ABORT\")", + .undef => .@"interrupt(\"UNDEF\")", + }, + + .avr_signal => .signal, + + .microblaze_interrupt => |opts| switch (opts.type) { + .user => .save_volatiles, + .regular => .interrupt_handler, + .fast => .fast_interrupt, + .breakpoint => .break_handler, + }, + + .mips_interrupt, .mips64_interrupt => |opts| switch (opts.mode) { + .eic => .@"interrupt(\"eic\")", + .sw0 => .@"interrupt(\"sw0\")", + .sw1 => .@"interrupt(\"sw1\")", + .hw0 => .@"interrupt(\"hw0\")", + .hw1 => .@"interrupt(\"hw1\")", + .hw2 => .@"interrupt(\"hw2\")", + .hw3 => .@"interrupt(\"hw3\")", + .hw4 => .@"interrupt(\"hw4\")", + .hw5 => .@"interrupt(\"hw5\")", + }, + + .riscv64_lp64_v, .riscv32_ilp32_v => .riscv_vector_cc, + .riscv32_interrupt, .riscv64_interrupt => |opts| switch (opts.mode) { + .supervisor => .@"interrupt(\"supervisor\")", + .machine => .@"interrupt(\"machine\")", + }, + + .sh_renesas => .renesas, + .sh_interrupt => |opts| switch (opts.save) { + .fpscr => .trapa_handler, + .high => .@"interrupt_handler, nosave_low_regs", + .full => .interrupt_handler, + .bank => .@"interrupt_handler, resbank", + }, + + .m68k_rtd => .m68k_rtd, + + .avr_interrupt, + .csky_interrupt, + .m68k_interrupt, + .msp430_interrupt, + .x86_16_interrupt, + .x86_interrupt, + .x86_64_interrupt, + => .interrupt, + + .ez80_tiflags => .tiflags, + + else => unreachable, // `Zcu.callconvSupported` + }; + } + }; + /// Returns `true` if this node has a postfix operator, meaning an `[...]` or `(...)` appears /// after the identifier in a declarator with this type. In this case, if this node is wrapped /// in a pointer type, we will need to add parentheses due to operator precedence. @@ -130,28 +297,28 @@ pub const CType = union(enum) { pub fn bits(int: Int, target: *const std.Target) u16 { return switch (int) { // zig fmt: off - .char => target.cTypeBitSize(.char), + .char => target.cTypeBitSize(.char).?, - .@"unsigned short" => target.cTypeBitSize(.ushort), - .@"unsigned int" => target.cTypeBitSize(.uint), - .@"unsigned long" => target.cTypeBitSize(.ulong), - .@"unsigned long long" => target.cTypeBitSize(.ulonglong), + .@"unsigned short" => target.cTypeBitSize(.ushort).?, + .@"unsigned int" => target.cTypeBitSize(.uint).?, + .@"unsigned long" => target.cTypeBitSize(.ulong).?, + .@"unsigned long long" => target.cTypeBitSize(.ulonglong).?, - .@"signed short" => target.cTypeBitSize(.short), - .@"signed int" => target.cTypeBitSize(.int), - .@"signed long" => target.cTypeBitSize(.long), - .@"signed long long" => target.cTypeBitSize(.longlong), + .@"signed short" => target.cTypeBitSize(.short).?, + .@"signed int" => target.cTypeBitSize(.int).?, + .@"signed long" => target.cTypeBitSize(.long).?, + .@"signed long long" => target.cTypeBitSize(.longlong).?, - .uintptr_t, .intptr_t => target.ptrBitWidth(), + .uintptr_t, .intptr_t => target.ptrBitWidth(), - .uint8_t, .int8_t => 8, - .uint16_t, .int16_t => 16, - .uint24_t, .int24_t => 24, - .uint32_t, .int32_t => 32, - .uint48_t, .int48_t => 48, - .uint64_t, .int64_t => 64, - .zig_u128, .zig_i128 => 128, - // zig fmt: on + .uint8_t, .int8_t => 8, + .uint16_t, .int16_t => 16, + .uint24_t, .int24_t => 24, + .uint32_t, .int32_t => 32, + .uint48_t, .int48_t => 48, + .uint64_t, .int64_t => 64, + .zig_u128, .zig_i128 => 128, + // zig fmt: on }; } }; @@ -376,6 +543,7 @@ pub const CType = union(enum) { .ret_ty = ret_cty_buf, .param_tys = param_cty_buf, .varargs = func_type.is_var_args, + .cc = .fromLang(func_type.cc, zcu.getTarget()), } }; } try deps.addType(gpa, cur_ty, allow_incomplete); @@ -763,6 +931,13 @@ pub const CType = union(enum) { try w.writeByte('('); }, } + switch (ptr.elem_ty.*) { + else => {}, + .function => |function| switch (function.cc) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + }, + } try w.writeByte('*'); }, @@ -812,7 +987,7 @@ pub const CType = union(enum) { => {}, .pointer => |ptr| { - // Match opening paren "(" write `writeTypePrefix`. + // Match opening paren "(" in `writeTypePrefix`. switch (ptr.elem_ty.kind()) { .specifier, .pointer => {}, .postfix_op => try w.writeByte(')'), diff --git a/src/codegen/c/type/render_defs.zig b/src/codegen/c/type/render_defs.zig index 03aae41ee0ec47cca9b560bd358263a5b0cb2352..2ba76d64eda0073dc0cdb032d117fedf16fba0ae 100644 --- a/src/codegen/c/type/render_defs.zig +++ b/src/codegen/c/type/render_defs.zig @@ -21,16 +21,21 @@ pub fn defineAligned( if (complete and alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); } - try w.print("{f}{f}{f}; /* align({d}) {f} */\n", .{ + try w.print("{f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), + }); + if (!zcu.comp.config.root_strip) try w.print(" /* align({d}) {f} */", .{ alignment.toByteUnits().?, ty.fmt(pt), }); + try w.writeByte('\n'); } /// Renders the definition of a big-int `struct`. pub fn defineBigInt(big: CType.BigInt, w: *Writer, zcu: *const Zcu) Writer.Error!void { + const target = zcu.getTarget(); + const bits = big.limb_size.bits() *| big.limbs_len; const name_cty: CType = .{ .bigint = .{ .limb_size = big.limb_size, .limbs_len = big.limbs_len, @@ -41,12 +46,20 @@ pub fn defineBigInt(big: CType.BigInt, w: *Writer, zcu: *const Zcu) Writer.Error .elem_ty = &limb_cty, .nonstring = limb_cty.isStringElem(), } }; - try w.print("{f} {{ {f}limbs{f}; }}; /* {d} bits */\n", .{ + try w.print("{f} {{ {f}limbs{f}; }};", .{ name_cty.fmtTypeName(zcu), array_cty.fmtDeclaratorPrefix(zcu), array_cty.fmtDeclaratorSuffix(zcu), - big.limb_size.bits() * @as(u17, big.limbs_len), }); + if (!zcu.comp.config.root_strip) try w.print(" /* u{d}, i{d} */", .{ bits, bits }); + try w.writeByte('\n'); + try writeStaticAssertCTypeLayout( + name_cty, + std.zig.target.intByteSize(target, bits), + .fromByteUnits(std.zig.target.intAlignment(target, bits)), + w, + zcu, + ); } /// Renders a forward declaration of the `struct` which represents an error union whose payload type @@ -81,27 +94,28 @@ pub fn errunionDefineComplete( if (payload_ty.hasRuntimeBits(zcu)) { const payload_cty: CType = try .lower(payload_ty, deps, arena, zcu); try w.print( - \\{f} {{ /* anyerror!{f} */ + \\{f} {{ \\ {f}payload{f}; \\ {f}error{f}; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - payload_ty.fmt(pt), payload_cty.fmtDeclaratorPrefix(zcu), payload_cty.fmtDeclaratorSuffix(zcu), error_cty.fmtDeclaratorPrefix(zcu), error_cty.fmtDeclaratorSuffix(zcu), }); } else { - try w.print("{f} {{ {f}error{f}; }}; /* anyerror!{f} */\n", .{ + try w.print("{f} {{ {f}error{f}; }};", .{ name_cty.fmtTypeName(zcu), error_cty.fmtDeclaratorPrefix(zcu), error_cty.fmtDeclaratorSuffix(zcu), - payload_ty.fmt(pt), }); } + if (!zcu.comp.config.root_strip) try w.print(" /* anyerror!{f} */", .{ + payload_ty.fmt(pt), + }); + try w.writeByte('\n'); } /// If the Zig type `ty` lowers to a `struct` or `union` type, renders a forward declaration of that @@ -141,10 +155,13 @@ pub fn defineIncomplete(ty: Type, w: *Writer, pt: Zcu.PerThread) Writer.Error!vo }, else => return, }; - try w.print("typedef void {f}; /* {f} */\n", .{ + try w.print("typedef void {f};", .{ name_cty.fmtTypeName(zcu), + }); + if (!zcu.comp.config.root_strip) try w.print(" /* {f} */", .{ ty.fmt(pt), }); + try w.writeByte('\n'); } /// If the Zig type `ty` lowers to a `struct` or `union` type, or to a `typedef`, renders the @@ -163,13 +180,13 @@ pub fn defineComplete( ty.assertHasLayout(zcu); - switch (ty.zigTypeTag(zcu)) { + const check_cty = check_cty: switch (ty.zigTypeTag(zcu)) { .@"fn" => if (!ty.fnHasRuntimeBits(zcu)) { const name_cty: CType = .{ .@"fn" = ty }; - try w.print("typedef void {f}; /* {f} */\n", .{ + try w.print("typedef void {f};", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); + break :check_cty null; } else { const ip = &zcu.intern_pool; const func_type = ip.indexToKey(ty.toIntern()).func_type; @@ -186,10 +203,12 @@ pub fn defineComplete( const name_cty: CType = .{ .@"fn" = ty }; const ret_cty: CType = try .lower(effective_ret_ty, deps, arena, zcu); - try w.print("typedef {f}{f}(", .{ - ret_cty.fmtDeclaratorPrefix(zcu), - name_cty.fmtTypeName(zcu), - }); + try w.print("typedef {f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); + switch (CType.CallingConvention.fromLang(func_type.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + } + try w.print("{f}(", .{name_cty.fmtTypeName(zcu)}); var any_params = false; for (func_type.param_types.get(ip)) |param_ty_ip| { const param_ty: Type = .fromInterned(param_ty_ip); @@ -205,88 +224,85 @@ pub fn defineComplete( } else if (!any_params) { try w.writeAll("void"); } - try w.print("){f}; /* {f} */\n", .{ - ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu), - ty.fmt(pt), - }); + try w.print("){f};", .{ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu)}); + break :check_cty null; }, .@"enum" => { const name_cty: CType = .{ .@"enum" = ty }; const cty: CType = try .lower(ty.backingIntType(zcu), deps, arena, zcu); - try w.print("typedef {f}{f}{f}; /* {f} */\n", .{ + try w.print("typedef {f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); + break :check_cty null; }, - .@"struct" => if (ty.isTuple(zcu)) { - try defineTuple(ty, deps, arena, w, pt); - } else switch (ty.containerLayout(zcu)) { - .auto, .@"extern" => try defineStruct(ty, deps, arena, w, pt), + .@"struct" => if (ty.isTuple(zcu)) + if (ty.hasRuntimeBits(zcu)) try defineTuple(ty, deps, arena, w, pt) else return + else switch (ty.containerLayout(zcu)) { + .auto, .@"extern" => if (ty.hasRuntimeBits(zcu)) try defineStruct(ty, deps, arena, w, pt) else return, .@"packed" => try defineBitpack(ty, deps, arena, w, pt), }, .@"union" => switch (ty.containerLayout(zcu)) { - .auto => try defineUnionAuto(ty, deps, arena, w, pt), - .@"extern" => try defineUnionExtern(ty, deps, arena, w, pt), + .auto => if (ty.hasRuntimeBits(zcu)) try defineUnionAuto(ty, deps, arena, w, pt) else return, + .@"extern" => if (ty.hasRuntimeBits(zcu)) try defineUnionExtern(ty, deps, arena, w, pt) else return, .@"packed" => try defineBitpack(ty, deps, arena, w, pt), }, .pointer => if (ty.isSlice(zcu)) { const name_cty: CType = .{ .slice = ty }; const ptr_cty: CType = try .lower(ty.slicePtrFieldType(zcu), deps, arena, zcu); try w.print( - \\{f} {{ /* {f} */ + \\{f} {{ \\ {f}ptr{f}; - \\ size_t len; + \\ uintptr_t len; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), ptr_cty.fmtDeclaratorPrefix(zcu), ptr_cty.fmtDeclaratorSuffix(zcu), }); - // Don't bother with `writeStaticAssertLayout`---there's not really any way we could mess - // slices up, and they're all obviously the same layout. - }, + break :check_cty switch (ty.toIntern()) { + .slice_const_u8_sentinel_0_type => name_cty, + else => null, + }; + } else return, .optional => switch (CType.classifyOptional(ty, zcu)) { .error_set, .ptr_like, .slice_like, .npv_payload, - => {}, + => return, .opv_payload => { const name_cty: CType = .{ .opt = ty }; - try w.print("{f} {{ bool is_null; }}; /* {f} */\n", .{ + try w.print("{f} {{ bool is_null; }};", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); + break :check_cty switch (ty.toIntern()) { + .optional_noreturn_type => name_cty, + else => null, + }; }, .@"struct" => { const name_cty: CType = .{ .opt = ty }; const payload_cty: CType = try .lower(ty.optionalChild(zcu), deps, arena, zcu); try w.print( - \\{f} {{ /* {f} */ + \\{f} {{ \\ {f}payload{f}; \\ bool is_null; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), payload_cty.fmtDeclaratorPrefix(zcu), payload_cty.fmtDeclaratorSuffix(zcu), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); + break :check_cty name_cty; }, }, .array => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .arr = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, @@ -296,43 +312,35 @@ pub fn defineComplete( break :nonstring Value.compareHetero(s, .neq, .zero_comptime_int, zcu); }, } }; - if (elem_ty.defaultStructFieldAlignment(.auto, zcu) == elem_ty.abiAlignment(zcu)) { - try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } else { - try w.print("zig_packed({f} {{ zig_under_align({d}) {f}array{f}; }}); /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - elem_ty.abiAlignment(zcu).toByteUnits().?, - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } - try writeStaticAssertLayout(ty, name_cty, w, zcu); - }, + try w.print("{f} {{ {f}array{f}; }};", .{ + name_cty.fmtTypeName(zcu), + array_cty.fmtDeclaratorPrefix(zcu), + array_cty.fmtDeclaratorSuffix(zcu), + }); + break :check_cty name_cty; + } else return, .vector => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .vec = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, .nonstring = elem_cty.isStringElem(), } }; - try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ + try w.print("{f} {{ {f}array{f}; }};", .{ name_cty.fmtTypeName(zcu), array_cty.fmtDeclaratorPrefix(zcu), array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); - }, - else => {}, - } + break :check_cty name_cty; + } else return, + else => return, + }; + if (!zcu.comp.config.root_strip) try w.print(" /* {f} */", .{ + ty.fmt(pt), + }); + try w.writeByte('\n'); + if (check_cty) |cty| try writeStaticAssertTypeLayout(ty, cty, w, zcu); } fn defineBitpack( ty: Type, @@ -340,16 +348,16 @@ fn defineBitpack( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!?CType { const zcu = pt.zcu; const name_cty: CType = .{ .bitpack = ty }; const cty: CType = try .lower(ty.backingIntType(zcu), deps, arena, zcu); - try w.print("typedef {f}{f}{f}; /* {f} */\n", .{ + try w.print("typedef {f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); + return null; } fn defineTuple( ty: Type, @@ -357,72 +365,54 @@ fn defineTuple( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const tuple = ip.indexToKey(ty.toIntern()).tuple_type; + // Fields cannot be underaligned, because tuple fields cannot have specified alignments. + // However, overaligned fields are possible thanks to intermediate zero-bit fields. + const tuple_align = ty.abiAlignment(zcu); - // If there are any underaligned fields, we need to byte-pack the tuple. - const pack: bool = pack: { - var offset: u64 = 0; - for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - const natural_offset = natural_align.forward(offset); - offset = field_ty.abiAlignment(zcu).forward(offset); - if (offset < natural_offset) break :pack true; - // Also pack if any field is more aligned than the tuple should be. - if (natural_align.compareStrict(.gt, tuple_align)) break :pack true; - offset += field_ty.abiSize(zcu); - } - break :pack false; - }; - // If the alignment of other fields would not give the tuple sufficient alignment, we // need to align the first field (which does not affect its offset, because 0 is always // well-aligned) to indirectly specify the tuple alignment. - const overalign: bool = switch (pack) { - true => tuple_align.compareStrict(.gt, .@"1"), - false => for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - if (natural_align.compareStrict(.gte, tuple_align)) break false; - } else true, - }; + const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| { + const field_ty: Type = .fromInterned(field_ty_ip); + if (!field_ty.hasRuntimeBits(zcu)) continue; + const natural_align = field_ty.abiAlignment(zcu); + if (natural_align.compareStrict(.gte, tuple_align)) break false; + } else true; - if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .@"struct" = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); var zig_offset: u64 = 0; var c_offset: u64 = 0; for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val_ip, field_index| { if (field_val_ip != .none) continue; // `comptime` field const field_ty: Type = .fromInterned(field_ty_ip); - zig_offset = field_ty.abiAlignment(zcu).forward(zig_offset); + const field_align = field_ty.abiAlignment(zcu); + zig_offset = field_align.forward(zig_offset); if (!field_ty.hasRuntimeBits(zcu)) continue; - if (!pack) c_offset = field_ty.defaultStructFieldAlignment(.auto, zcu).forward(c_offset); + c_offset = field_align.forward(c_offset); try w.writeByte(' '); if (zig_offset == 0 and overalign) { // This is the first field; specify its alignment to align the tuple. try writeFieldAlign(field_ty, tuple_align, w, zcu); - } else if (zig_offset > c_offset) { - // This field needs to be underaligned or overaligned compared to what its - // offset would otherwise be. - const need_align: Alignment = .minStrict( - tuple_align, // don't make the tuple more aligned than it should be - .fromLog2Units(@ctz(zig_offset)), - ); - try writeFieldAlign(field_ty, need_align, w, zcu); - c_offset = need_align.forward(c_offset); + } else switch (zig_offset - c_offset) { + 0 => {}, + else => |need_bytes| { + // This field needs to be overaligned compared to what its offset would otherwise be. + const need_align: Alignment = .fromLog2Units(std.math.log2_int(u64, need_bytes) + 1); + assert(need_align.compareStrict(.lte, tuple_align)); + try writeFieldAlign(field_ty, need_align, w, zcu); + c_offset = need_align.forward(c_offset); + }, } + assert(c_offset == zig_offset); const field_cty: CType = try .lower(field_ty, deps, arena, zcu); try w.print("{f}f{d}{f};\n", .{ field_cty.fmtDeclaratorPrefix(zcu), @@ -433,11 +423,8 @@ fn defineTuple( zig_offset += field_size; c_offset += field_size; } - try w.writeByte('}'); - if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeAll("};"); + return name_cty; } fn defineStruct( ty: Type, @@ -445,9 +432,8 @@ fn defineStruct( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const struct_type = ip.loadStructType(ty.toIntern()); @@ -459,7 +445,7 @@ fn defineStruct( while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); const natural_offset = natural_align.forward(offset); const actual_offset = struct_type.field_offsets.get(ip)[field_index]; if (actual_offset < natural_offset) break :pack true; @@ -480,7 +466,7 @@ fn defineStruct( while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, struct_type.alignment)) break :overalign false; } break :overalign true; @@ -489,16 +475,15 @@ fn defineStruct( if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .@"struct" = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); var it = struct_type.iterateRuntimeOrder(ip); var offset: u64 = 0; while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); const natural_offset = switch (pack) { true => offset, false => natural_align.forward(offset), @@ -529,9 +514,8 @@ fn defineStruct( assert(struct_type.alignment.forward(offset) == struct_type.size); try w.writeByte('}'); if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeByte(';'); + return name_cty; } fn defineUnionAuto( ty: Type, @@ -539,9 +523,8 @@ fn defineUnionAuto( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const union_type = ip.loadUnionType(ty.toIntern()); @@ -553,7 +536,7 @@ fn defineUnionAuto( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; // The tag will immediately follow the payload. This layout may put the tag in what would // otherwise be padding on the payload union, because if the most-aligned union field is not @@ -571,7 +554,7 @@ fn defineUnionAuto( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -585,9 +568,8 @@ fn defineUnionAuto( const payload_has_bits = !union_type.has_runtime_tag or union_type.size > enum_tag_ty.abiSize(zcu); const name_cty: CType = .{ .union_auto = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); if (payload_has_bits) { try w.writeByte(' '); @@ -619,9 +601,8 @@ fn defineUnionAuto( tag_cty.fmtDeclaratorSuffix(zcu), }); } - try w.writeAll("};\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeAll("};"); + return name_cty; } fn defineUnionExtern( ty: Type, @@ -629,9 +610,8 @@ fn defineUnionExtern( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const union_type = ip.loadUnionType(ty.toIntern()); @@ -642,7 +622,7 @@ fn defineUnionExtern( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; } else false; @@ -654,7 +634,7 @@ fn defineUnionExtern( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -668,9 +648,8 @@ fn defineUnionExtern( if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .union_extern = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); for (0..enum_tag_ty.enumFieldCount(zcu)) |field_index| { @@ -691,9 +670,8 @@ fn defineUnionExtern( } try w.writeByte('}'); if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeByte(';'); + return name_cty; } /// Writes an annotation which, placed before a struct/union field declaration with field type `ty`, @@ -704,7 +682,7 @@ fn writeFieldAlign( w: *Writer, zcu: *const Zcu, ) Writer.Error!void { - if (alignment.compareStrict(.lt, ty.defaultStructFieldAlignment(.auto, zcu))) { + if (alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); } else { try w.print("zig_align({d}) ", .{alignment.toByteUnits().?}); @@ -712,19 +690,29 @@ fn writeFieldAlign( } /// Emits static assertions that the size and alignment of `cty` match those of the Zig type `ty`. -fn writeStaticAssertLayout( +pub fn writeStaticAssertTypeLayout( ty: Type, cty: CType, w: *Writer, zcu: *const Zcu, +) Writer.Error!void { + try writeStaticAssertCTypeLayout(cty, ty.abiSize(zcu), ty.abiAlignment(zcu), w, zcu); +} + +/// Emits static assertions that the size and alignment of `cty` match the provided values. +pub fn writeStaticAssertCTypeLayout( + cty: CType, + expected_size: u64, + expected_alignment: Alignment, + w: *Writer, + zcu: *const Zcu, ) Writer.Error!void { try w.print( - \\zig_static_assert(sizeof ({f}) == {d}, "incorrect size"); - \\zig_static_assert(_Alignof ({f}) == {d}, "incorrect alignment"); + \\zig_static_assert(sizeof({f}) == {d} && zig_alignOf({f}) == {d}, "abi mismatch"); \\ , .{ - cty.fmtTypeName(zcu), ty.abiSize(zcu), - cty.fmtTypeName(zcu), ty.abiAlignment(zcu).toByteUnits().?, + cty.fmtTypeName(zcu), expected_size, + cty.fmtTypeName(zcu), expected_alignment.toByteUnits().?, }); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 12422f9f6f8ba5609730e1f38e37960951409174..31e67026821a109d79a6e677014fa0bcf8712615 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -345,160 +345,6 @@ pub fn supportsTailCall(target: *const std.Target) bool { }; } -pub fn dataLayout(target: *const std.Target) []const u8 { - // These data layouts should match Clang. - return switch (target.cpu.arch) { - .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32", - .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32", - .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048", - .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64", - .aarch64 => if (target.ofmt == .macho) - if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else if (target.abi == .ilp32) - "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" - else - "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", - .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", - .arm => if (target.ofmt == .macho) - "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .armeb, .thumbeb => if (target.ofmt == .macho) - "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .thumb => if (target.ofmt == .macho) - "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8", - .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16", - .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", - .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", - .mips64 => switch (target.abi) { - .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - }, - .mips64el => switch (target.abi) { - .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - }, - .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16", - .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32", - .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32", - .powerpc64 => switch (target.os.tag) { - .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", - .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64", - else => "E-m:e-Fn32-i64:64-i128:128-n32:64", - }, - .powerpc64le => if (target.os.tag == .linux) - "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" - else - "e-m:e-Fn32-i64:64-i128:128-n32:64", - .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", - .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", - .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9", - .riscv32 => if (target.cpu.has(.riscv, .e)) - "e-m:e-p:32:32-i64:64-n32-S32" - else - "e-m:e-p:32:32-i64:64-n32-S128", - .riscv32be => if (target.cpu.has(.riscv, .e)) - "E-m:e-p:32:32-i64:64-n32-S32" - else - "E-m:e-p:32:32-i64:64-n32-S128", - .riscv64 => if (target.cpu.has(.riscv, .e)) - "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64" - else - "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .riscv64be => if (target.cpu.has(.riscv, .e)) - "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64" - else - "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64", - .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128", - .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64", - .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) { - .gnu => if (target.ofmt == .coff) - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32", - else => blk: { - const msvc = switch (target.abi) { - .none, .msvc => true, - else => false, - }; - - break :blk if (target.ofmt == .coff) - if (msvc) - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" - else - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" - else if (msvc) - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"; - }, - } else if (target.ofmt == .macho) - "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", - .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho) - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" - else switch (target.abi) { - .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", - else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff) - "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" - else - "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", - }, - .spirv32 => switch (target.os.tag) { - .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - }, - .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - .wasm32 => if (target.os.tag == .emscripten) - "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" - else - "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", - .wasm64 => if (target.os.tag == .emscripten) - "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" - else - "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", - .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64", - .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32", - .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128", - .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32", - - .alpha, - .arceb, - .ez80, - .hppa, - .hppa64, - .kalimba, - .kvx, - .m88k, - .microblaze, - .microblazeel, - .or1k, - .propeller, - .sh, - .sheb, - .x86_16, - .xtensaeb, - => unreachable, // Gated by hasLlvmSupport(). - }; -} - // Avoid depending on `bindings.CodeModel` in the bitcode-only case. const CodeModel = enum { default, @@ -573,6 +419,8 @@ pub const Object = struct { val: InternPool.Index, @"addrspace": std.lang.AddressSpace, }, Builder.Variable.Index), + /// Same as `uav_map` but for llvm values not originating from the frontend. + const_map: std.AutoHashMapUnmanaged(Builder.Constant, Builder.Variable.Index), /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction. enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index), /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction. @@ -616,8 +464,6 @@ pub const Object = struct { }); errdefer builder.deinit(); - builder.data_layout = try builder.string(dataLayout(target)); - const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref = if (!builder.strip) debug_info: { // We fully resolve all paths at this point to avoid lack of @@ -693,6 +539,7 @@ pub const Object = struct { .zcu = zcu, .nav_map = .empty, .uav_map = .empty, + .const_map = .empty, .enum_tag_name_map = .empty, .named_enum_map = .empty, .type_map = .empty, @@ -703,21 +550,22 @@ pub const Object = struct { return obj; } - pub fn deinit(self: *Object) void { - const gpa = self.gpa; - self.type_pool.deinit(gpa); - self.lazy_abi_aligns.deinit(gpa); - self.debug_enums.deinit(gpa); - self.debug_globals.deinit(gpa); - self.debug_file_map.deinit(gpa); - self.debug_types.deinit(gpa); - self.nav_map.deinit(gpa); - self.uav_map.deinit(gpa); - self.enum_tag_name_map.deinit(gpa); - self.named_enum_map.deinit(gpa); - self.type_map.deinit(gpa); - self.builder.deinit(); - self.* = undefined; + pub fn deinit(o: *Object) void { + const gpa = o.gpa; + o.type_pool.deinit(gpa); + o.lazy_abi_aligns.deinit(gpa); + o.debug_enums.deinit(gpa); + o.debug_globals.deinit(gpa); + o.debug_file_map.deinit(gpa); + o.debug_types.deinit(gpa); + o.nav_map.deinit(gpa); + o.uav_map.deinit(gpa); + o.const_map.deinit(gpa); + o.enum_tag_name_map.deinit(gpa); + o.named_enum_map.deinit(gpa); + o.type_map.deinit(gpa); + o.builder.deinit(); + o.* = undefined; } fn genErrorNameTable(o: *Object) Allocator.Error!void { @@ -741,16 +589,16 @@ pub const Object = struct { for (llvm_errors[1..], error_name_list) |*llvm_error, name| { const name_string = try o.builder.stringNull(name.toSlice(ip)); const name_init = try o.builder.stringConst(name_string); - const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); - try name_variable_index.setInitializer(name_init, &o.builder); - name_variable_index.setMutability(.constant, &o.builder); - name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder); - const global_index = name_variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, &o.builder); - global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); + try name_llvm_variable.setInitializer(name_init, &o.builder); + name_llvm_variable.setMutability(.constant, &o.builder); + name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); + const llvm_global = name_llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ - name_variable_index.toConst(&o.builder), + name_llvm_variable.toConst(&o.builder), try o.builder.intConst(llvm_usize_ty, name_string.slice(&o.builder).?.len - 1), }); } @@ -1199,19 +1047,33 @@ pub const Object = struct { global.dll_storage_class = .default; global.unnamed_addr = .unnamed_addr; } - llvm_function.setAlignment(switch (nav.resolved.?.@"align") { - .none => fn_ty.abiAlignment(zcu).toLlvm(), - else => |a| a.toLlvm(), - }, &o.builder); + llvm_function.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder); llvm_function.setSection(s: { const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none; break :s try o.builder.string(section); }, &o.builder); - try o.addLlvmFunctionAttributes(pt, func.owner_nav, llvm_function); - var attributes = try llvm_function.ptrConst(&o.builder).attributes.toWip(&o.builder); + var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); + // Function attributes that are independent of analysis results of the function body. + try o.addCommonFnAttributes( + &attributes, + owner_mod, + // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`, + // so for these backends, LLVM will happily emit code that accesses the stack through + // the frame pointer. This is nonsensical since what the `naked` attribute does is + // suppress generation of the prologue and epilogue, and the prologue is where the + // frame pointer normally gets set up. At time of writing, this is the case for at + // least x86 and RISC-V. + owner_mod.omit_frame_pointer or fn_info.cc == .naked, + ); + + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, if (nav.getExtern(ip)) |@"extern"| .{ + .name = nav.name.toSlice(ip), + .lib_name = @"extern".lib_name.toSlice(ip), + } else null, .fromIntern(fn_info, ip)); + const func_analysis = func.analysisUnordered(ip); if (func_analysis.is_noinline) { try attributes.addFnAttr(.@"noinline", &o.builder); @@ -1324,7 +1186,7 @@ pub const Object = struct { const counters_variable = try o.builder.addVariable(anon_name, .void, .default); try o.used.append(gpa, counters_variable.toConst(&o.builder)); counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder); - counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); + counters_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); if (target.ofmt == .macho) { counters_variable.setSection(try o.builder.string("__DATA,__sancov_cntrs"), &o.builder); @@ -1507,10 +1369,6 @@ pub const Object = struct { llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr; } - const llvm_align = switch (resolved.@"align") { - .none => nav_ty.abiAlignment(zcu).toLlvm(), - else => |a| a.toLlvm(), - }; const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: { break :s try o.builder.string(section); } else .none; @@ -1519,13 +1377,20 @@ pub const Object = struct { // can see are extern functions or other comptime function body values (e.g. undefined). Of // these, only extern functions need to be lowered to LLVM functions. if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) { + const fn_info = zcu.typeToFunc(nav_ty).?; const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) { .function => |function| function, // re-use existing `Builder.Function` .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder), }; - llvm_function.setAlignment(llvm_align, &o.builder); + llvm_function.setAlignment(resolved.@"align".toLlvm(), &o.builder); llvm_function.setSection(llvm_section, &o.builder); - try o.addLlvmFunctionAttributes(pt, nav_id, llvm_function); + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{ + .name = nav.name.toSlice(ip), + .lib_name = opt_extern.?.lib_name.toSlice(ip), + }, .fromIntern(fn_info, ip)); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); } else { const file_scope = nav.srcInst(ip).resolveFile(ip); const mod = zcu.fileByIndex(file_scope).mod.?; @@ -1534,7 +1399,10 @@ pub const Object = struct { .variable => |variable| variable, // re-use existing `Builder.Variable` .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder), }; - llvm_variable.setAlignment(llvm_align, &o.builder); + llvm_variable.setAlignment(switch (resolved.@"align") { + .none => nav_ty.abiAlignment(zcu).toLlvm(), + else => |a| a.toLlvm(), + }, &o.builder); llvm_variable.setSection(llvm_section, &o.builder); llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder); try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder); @@ -1585,7 +1453,7 @@ pub const Object = struct { const uav_ty = Value.fromInterned(uav).typeOf(zcu); const uav_ref = try o.lowerUavRef( uav, - uav_ty.abiAlignment(zcu), + uav_ty.abiAlignment(zcu).toLlvm(), target_util.defaultAddressSpace(zcu.getTarget(), .global_constant), ); break :exp .{ uav_ty, uav_ref }; @@ -1599,7 +1467,7 @@ pub const Object = struct { fn updateExportedGlobal( o: *Object, - global_index: Builder.Global.Index, + llvm_global: Builder.Global.Index, ty: Type, export_indices: []const Zcu.Export.Index, ) link.Error!void { @@ -1634,11 +1502,11 @@ pub const Object = struct { // make much sense: the linksection should be associated with the declaration itself rather // than some particular symbol it is exported as! if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| { - const variable = &global_index.ptrConst(&o.builder).kind.variable; + const variable = &llvm_global.ptrConst(&o.builder).kind.variable; variable.setSection(try o.builder.string(section_slice), &o.builder); } - const llvm_global_ty = global_index.typeOf(&o.builder); + const llvm_global_ty = llvm_global.typeOf(&o.builder); // All exports are represented as aliases to the original global. @@ -1661,8 +1529,8 @@ pub const Object = struct { const alias = try o.builder.addAlias( exp_name, llvm_global_ty, - global_index.ptrConst(&o.builder).addr_space, - global_index.toConst(), + llvm_global.ptrConst(&o.builder).addr_space, + llvm_global.toConst(), ); break :global alias.ptrConst(&o.builder).global; }; @@ -1671,12 +1539,9 @@ pub const Object = struct { switch (existing_global.ptrConst(&o.builder).kind) { .alias => |alias| { // We can just repurpose the existing alias. - alias.setAliasee(global_index.toConst(), &o.builder); - alias.ptrConst(&o.builder).global.ptr(&o.builder).type = global_index.typeOf(&o.builder); - // If the type the alias is pointing to can change, then - // it makes sense that we should update the address - // space too. - alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = global_index.ptrConst(&o.builder).addr_space; + alias.setAliasee(llvm_global.toConst(), &o.builder); + alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder); + alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; break :global existing_global; }, .variable, .function => { @@ -1686,13 +1551,13 @@ pub const Object = struct { // We need to make a new global which is an alias. Replace this existing one // with the target global, making the name available and fixing references // to this global to point to the target. - try existing_global.replace(global_index, &o.builder); + try existing_global.replace(llvm_global, &o.builder); // The name is now free, so create an alias. const alias = try o.builder.addAlias( exp_name, llvm_global_ty, - global_index.ptrConst(&o.builder).addr_space, - global_index.toConst(), + llvm_global.ptrConst(&o.builder).addr_space, + llvm_global.toConst(), ); break :global alias.ptrConst(&o.builder).global; }, @@ -1725,11 +1590,11 @@ pub const Object = struct { pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void { _ = o.type_map.remove(ty); try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success); - if (o.named_enum_map.get(ty)) |function_index| { - try o.updateIsNamedEnumValueFunction(.fromInterned(ty), function_index); + if (o.named_enum_map.get(ty)) |llvm_function| { + try o.updateIsNamedEnumValueFunction(.fromInterned(ty), llvm_function); } - if (o.enum_tag_name_map.get(ty)) |function_index| { - try o.updateEnumTagNameFunction(.fromInterned(ty), function_index); + if (o.enum_tag_name_map.get(ty)) |llvm_function| { + try o.updateEnumTagNameFunction(.fromInterned(ty), llvm_function); } } @@ -2102,7 +1967,7 @@ pub const Object = struct { payload_offset * 8, ); - return try o.builder.debugStructType( + return o.builder.debugStructType( name, null, // File o.debug_compile_unit.unwrap().?, // Scope @@ -2140,7 +2005,7 @@ pub const Object = struct { defer debug_param_types.deinit(gpa); // Return type goes first. - if (try fnReturnStrat(o, fn_info) == .sret) { + if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) { // Actual return type is void, then first arg is the sret pointer. const ptr_ty = try pt.singleMutPtrType(.fromInterned(fn_info.return_type)); debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .void)); @@ -2575,53 +2440,117 @@ pub const Object = struct { fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata { const zcu = o.zcu; const namespace = zcu.namespacePtr(namespace_index); - if (namespace.parent == .none) return try o.getDebugFile(namespace.file_scope); + if (namespace.parent == .none) return o.getDebugFile(namespace.file_scope); return o.getDebugType(pt, .fromInterned(namespace.owner_type)); } - /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the - /// given `Nav` (which is a function). - fn addLlvmFunctionAttributes( + fn addCommonFnAttributes( + o: *Object, + attributes: *Builder.FunctionAttributes.Wip, + owner_mod: *Module, + omit_frame_pointer: bool, + ) Allocator.Error!void { + if (!owner_mod.red_zone) { + try attributes.addFnAttr(.noredzone, &o.builder); + } + if (omit_frame_pointer) { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("frame-pointer"), + .value = try o.builder.string("none"), + } }, &o.builder); + } else { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("frame-pointer"), + .value = try o.builder.string("all"), + } }, &o.builder); + } + try attributes.addFnAttr(.nounwind, &o.builder); + if (owner_mod.unwind_tables != .none) { + try attributes.addFnAttr( + .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync }, + &o.builder, + ); + } + if (owner_mod.optimize_mode == .small) { + try attributes.addFnAttr(.minsize, &o.builder); + try attributes.addFnAttr(.optsize, &o.builder); + } + const target = &owner_mod.resolved_target.result; + if (target.cpu.model.llvm_name) |s| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("target-cpu"), + .value = try o.builder.string(s), + } }, &o.builder); + } + if (owner_mod.resolved_target.llvm_cpu_features) |s| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("target-features"), + .value = try o.builder.string(std.mem.span(s)), + } }, &o.builder); + } + if (target.abi.float() == .soft) { + // `use-soft-float` means "use software routines for floating point computations". In + // other words, it configures how LLVM lowers basic float instructions like `fcmp`, + // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is + // mostly an orthogonal concept, although obviously we do need hardware float operations + // to actually be able to pass float values in float registers. + // + // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC + // and Clang support for Arm32 and CSKY. We don't currently expose such an option in + // Zig, and using CPU features as the source of truth for this makes for a miserable + // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float + // unless the compiler has explicitly been told otherwise. (And note that our baseline + // CPU models almost all include FPU features!) + // + // Revisit this at some point. + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("use-soft-float"), + .value = try o.builder.string("true"), + } }, &o.builder); + + // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the + // above, this should be revisited if `softfp` support is added. + try attributes.addFnAttr(.noimplicitfloat, &o.builder); + } + } + + pub fn addCallingConventionFnAttributes( o: *Object, pt: Zcu.PerThread, - nav_id: InternPool.Nav.Index, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, + attributes: *Builder.FunctionAttributes.Wip, + opt_extern: ?struct { + name: []const u8, + lib_name: ?[]const u8 = null, + }, + fn_info: FuncInfo, ) Allocator.Error!void { const zcu = o.zcu; - const ip = &zcu.intern_pool; - const nav = ip.getNav(nav_id); - const owner_mod = zcu.navFileScope(nav_id).mod.?; - const ty: Type = .fromInterned(nav.resolved.?.type); - - const fn_info = zcu.typeToFunc(ty).?; - const target = &owner_mod.resolved_target.result; - - var attributes: Builder.FunctionAttributes.Wip = .{}; - defer attributes.deinit(&o.builder); - - if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("wasm-import-name"), - .value = try o.builder.string(nav.name.toSlice(ip)), - } }, &o.builder); - if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| { - if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("wasm-import-module"), - .value = try o.builder.string(lib_name_slice), - } }, &o.builder); - } - }; + const target = zcu.getTarget(); if (fn_info.cc == .async) { @panic("TODO: LLVM backend lower async function"); } + if (target.cpu.arch.isWasm()) if (opt_extern) |@"extern"| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("wasm-import-name"), + .value = try o.builder.string(@"extern".name), + } }, &o.builder); + if (@"extern".lib_name) |lib_name| { + if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("wasm-import-module"), + .value = try o.builder.string(lib_name), + } }, &o.builder); + } + }; + const cc_info = toLlvmCallConv(fn_info.cc, target).?; - function_index.setCallConv(cc_info.llvm_cc, &o.builder); + llvm_function.setCallConv(cc_info.llvm_cc, &o.builder); if (cc_info.align_stack) { - try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); + try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("stackrealign"), .value = .empty } }, &o.builder); } if (cc_info.naked) { @@ -2672,29 +2601,16 @@ pub const Object = struct { else => {}, } - // Function attributes that are independent of analysis results of the function body. - try o.addCommonFnAttributes( - &attributes, - owner_mod, - // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`, - // so for these backends, LLVM will happily emit code that accesses the stack through - // the frame pointer. This is nonsensical since what the `naked` attribute does is - // suppress generation of the prologue and epilogue, and the prologue is where the - // frame pointer normally gets set up. At time of writing, this is the case for at - // least x86 and RISC-V. - owner_mod.omit_frame_pointer or fn_info.cc == .naked, - ); - if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); - var it = iterateParamTypes(o, fn_info); - if (try fnReturnStrat(o, fn_info) == .sret) { - // Sret pointers must not be address 0 - try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); - try attributes.addParamAttr(it.llvm_index, .@"noalias", &o.builder); - - const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type), .in_memory); - try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); + if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) { + try o.addSRetFnAttributes( + attributes, + try o.lowerType(.fromInterned(fn_info.return_type), .in_memory), + Type.fromInterned(fn_info.return_type).abiAlignment(zcu).toLlvm(), + .declaration, + ); it.llvm_index += 1; } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { .signed => try attributes.addRetAttr(.signext, &o.builder), @@ -2713,9 +2629,9 @@ pub const Object = struct { while (try it.next()) |lowering| switch (lowering) { .byval => { const param_index = it.zig_index - 1; - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty: Type = .fromInterned(fn_info.param_types[param_index]); if (!isByRef(param_ty, zcu)) { - try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); + try o.addByValParamAttrs(pt, attributes, param_ty, param_index, fn_info, it.llvm_index - 1); } if (remaining_inreg_int > 0 and @@ -2734,12 +2650,12 @@ pub const Object = struct { } }, .byref => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty); + const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]); + try o.addByRefParamAttrs(attributes, it.llvm_index - 1, it.byval_attr, param_ty); }, .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), .slice => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]); const ptr_info = param_ty.ptrInfo(zcu); const llvm_ptr_index = it.llvm_index - 2; if (std.math.cast(u5, it.zig_index - 1)) |i| { @@ -2771,94 +2687,205 @@ pub const Object = struct { .i64_array, => continue, }; - - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); } - fn addCommonFnAttributes( + pub fn addSRetFnAttributes( o: *Object, attributes: *Builder.FunctionAttributes.Wip, - owner_mod: *Module, - omit_frame_pointer: bool, + ret_ty: Builder.Type, + ret_align: Builder.Alignment, + location: enum { declaration, callsite }, ) Allocator.Error!void { - if (!owner_mod.red_zone) { - try attributes.addFnAttr(.noredzone, &o.builder); - } - if (omit_frame_pointer) { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("frame-pointer"), - .value = try o.builder.string("none"), - } }, &o.builder); - } else { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("frame-pointer"), - .value = try o.builder.string("all"), - } }, &o.builder); - } - try attributes.addFnAttr(.nounwind, &o.builder); - if (owner_mod.unwind_tables != .none) { - try attributes.addFnAttr( - .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync }, - &o.builder, - ); - } - if (owner_mod.optimize_mode == .small) { - try attributes.addFnAttr(.minsize, &o.builder); - try attributes.addFnAttr(.optsize, &o.builder); - } - const target = &owner_mod.resolved_target.result; - if (target.cpu.model.llvm_name) |s| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("target-cpu"), - .value = try o.builder.string(s), - } }, &o.builder); - } - if (owner_mod.resolved_target.llvm_cpu_features) |s| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("target-features"), - .value = try o.builder.string(std.mem.span(s)), - } }, &o.builder); - } - if (target.abi.float() == .soft) { - // `use-soft-float` means "use software routines for floating point computations". In - // other words, it configures how LLVM lowers basic float instructions like `fcmp`, - // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is - // mostly an orthogonal concept, although obviously we do need hardware float operations - // to actually be able to pass float values in float registers. - // - // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC - // and Clang support for Arm32 and CSKY. We don't currently expose such an option in - // Zig, and using CPU features as the source of truth for this makes for a miserable - // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float - // unless the compiler has explicitly been told otherwise. (And note that our baseline - // CPU models almost all include FPU features!) - // - // Revisit this at some point. - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("use-soft-float"), - .value = try o.builder.string("true"), - } }, &o.builder); - - // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the - // above, this should be revisited if `softfp` support is added. - try attributes.addFnAttr(.noimplicitfloat, &o.builder); - } + try attributes.addParamAttr(0, .dead_on_unwind, &o.builder); + switch (location) { + .declaration => try attributes.addParamAttr(0, .@"noalias", &o.builder), + .callsite => {}, + } + try attributes.addParamAttr(0, .writeonly, &o.builder); + try attributes.addParamAttr(0, .{ .captures = .none }, &o.builder); + try attributes.addParamAttr(0, .{ .sret = ret_ty }, &o.builder); + try attributes.addParamAttr(0, .{ .@"align" = .wrap(ret_align) }, &o.builder); } pub const TypeRepr = enum { /// The representation of the type when it is being manipulated as a value in a function. - /// e.g. Zig `u5` -> LLVM `i5` - by_value, - /// The representation of the type when it is stored in memory. - /// e.g. Zig `u5` -> LLVM `i8` + /// e.g. Zig `u90` -> LLVM `i90` + as_value, + /// The representation of the type when it is loaded from or stored to memory. + /// e.g. Zig `u90` -> LLVM `i96` + memory_access, + /// The representation of the type when it is in memory. + /// e.g. Zig `u90` -> LLVM `[12 x i8]` in_memory, }; + pub fn intType(o: *Object, bits: u16, repr: TypeRepr) Allocator.Error!Builder.Type { + switch (repr) { + .as_value => return o.builder.intType(bits), + .memory_access, .in_memory => {}, + } + const target = o.zcu.getTarget(); + const abi_size = std.zig.target.intByteSize(target, bits); + const llvm_bit_width = @as(u20, 8) * abi_size; + switch (repr) { + .as_value => unreachable, + .memory_access => {}, + .in_memory => { + const zig_align = std.zig.target.intAlignment(target, bits); + const llvm_align = o.builder.data_layout.getIntegerSpec(llvm_bit_width).abi_align; + if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8); + }, + } + return o.builder.intType(llvm_bit_width); + } + pub fn errorIntType(o: *Object, repr: TypeRepr) Allocator.Error!Builder.Type { - return o.builder.intType(switch (repr) { - .by_value => o.zcu.errorSetBits(), - .in_memory => @intCast(Type.anyerror.abiSize(o.zcu) * 8), - }); + return o.intType(o.zcu.errorSetBits(), repr); + } + + pub const SoftF80Layout = struct { + alignment: InternPool.Alignment, + /// byte offset of u64 field + mantissa_offset: u64, + /// byte offset of u16 field + exponent_offset: u64, + llvm_fields_len: u32, + + pub const LlvmFieldTag = enum { mantissa, exponent, padding }; + }; + pub fn softF80Layout(o: *Object, opts: struct { + llvm_field_tags_buf: []SoftF80Layout.LlvmFieldTag = &.{}, + llvm_field_types_buf: []Builder.Type = &.{}, + }) Allocator.Error!SoftF80Layout { + const zcu = o.zcu; + const target = zcu.getTarget(); + assert(std.zig.target.compilerRtFloatAbi(target, 80) == .soft); + // Current compiler rt soft abi, which is not yet affected by endianness for simplicity: + // + // typedef struct { uint64_t mantissa; uint16_t exponent; } f80; + // + var layout: SoftF80Layout = .{ + .alignment = Type.f80.abiAlignment(zcu), + .mantissa_offset = undefined, + .exponent_offset = undefined, + .llvm_fields_len = 0, + }; + var offset: u64 = 0; + for ([2]SoftF80Layout.LlvmFieldTag{ .mantissa, .exponent }, [2]Type{ .u64, .u16 }) |field_tag, field_type| { + const field_align = field_type.abiAlignment(zcu); + assert(field_align.compareStrict(.lte, layout.alignment)); + const field_offset = field_align.forward(offset); + switch (field_offset - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + switch (field_tag) { + .mantissa => layout.mantissa_offset = field_offset, + .exponent => layout.exponent_offset = field_offset, + .padding => unreachable, + } + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory); + layout.llvm_fields_len += 1; + offset = field_offset + field_type.abiSize(zcu); + } + const end = layout.alignment.forward(offset); + assert(end == Type.f80.abiSize(zcu)); + switch (end - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + return layout; + } + + pub const SoftF128Layout = struct { + alignment: InternPool.Alignment, + /// byte offset of u64 field + lo_offset: u64, + /// byte offset of u64 field + hi_offset: u64, + llvm_fields_len: u32, + + pub const LlvmFieldTag = enum { lo, hi, padding }; + }; + pub fn softF128Layout(o: *Object, opts: struct { + llvm_field_tags_buf: []SoftF128Layout.LlvmFieldTag = &.{}, + llvm_field_types_buf: []Builder.Type = &.{}, + }) Allocator.Error!SoftF128Layout { + const zcu = o.zcu; + const target = zcu.getTarget(); + assert(std.zig.target.compilerRtFloatAbi(target, 128) == .soft); + // Current compiler rt soft abi: + // + // #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + // typedef struct { uint64_t hi, lo; } f128; + // #else + // typedef struct { uint64_t lo, hi; } f128; + // #endif + // + var layout: SoftF128Layout = .{ + .alignment = Type.f128.abiAlignment(zcu), + .lo_offset = undefined, + .hi_offset = undefined, + .llvm_fields_len = 0, + }; + var offset: u64 = 0; + for (@as([2]SoftF128Layout.LlvmFieldTag, switch (target.cpu.arch.endian()) { + .big => .{ .hi, .lo }, + .little => .{ .lo, .hi }, + }), [2]Type{ .u64, .u64 }) |field_tag, field_type| { + const field_align = field_type.abiAlignment(zcu); + assert(field_align.compareStrict(.lte, layout.alignment)); + const field_offset = field_align.forward(offset); + switch (field_offset - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + switch (field_tag) { + .lo => layout.lo_offset = field_offset, + .hi => layout.hi_offset = field_offset, + .padding => unreachable, + } + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory); + layout.llvm_fields_len += 1; + offset = field_offset + field_type.abiSize(zcu); + } + const end = layout.alignment.forward(offset); + assert(end == Type.f128.abiSize(zcu)); + switch (end - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + return layout; } pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type { @@ -2866,42 +2893,31 @@ pub const Object = struct { const target = zcu.getTarget(); const ip = &zcu.intern_pool; - if (repr == .by_value) { - assert(!isByRef(t, zcu)); // by-ref types must only be manipulated in memory + switch (repr) { + .as_value => assert(!isByRef(t, zcu)), // by-ref types must only be manipulated in memory + .memory_access, .in_memory => {}, } return switch (t.toIntern()) { .u0_type => unreachable, // no runtime bits - inline .u1_type, - .u8_type, - .i8_type, - .u16_type, - .i16_type, - .u29_type, - .u32_type, - .i32_type, - .u64_type, - .i64_type, - .u80_type, - .u128_type, - .i128_type, - => |tag| switch (repr) { - .by_value => @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]), - .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)), - }, - .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()), - inline .c_char_type, - .c_short_type, - .c_ushort_type, - .c_int_type, - .c_uint_type, - .c_long_type, - .c_ulong_type, - .c_longlong_type, - .c_ulonglong_type, - => |tag| try o.builder.intType(target.cTypeBitSize( - @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]), - )), + .u1_type => try o.intType(1, repr), + .u8_type, .i8_type => try o.intType(8, repr), + .u16_type, .i16_type => try o.intType(16, repr), + .u29_type => try o.intType(29, repr), + .u32_type, .i32_type => try o.intType(32, repr), + .u64_type, .i64_type => try o.intType(64, repr), + .u80_type => try o.intType(80, repr), + .u128_type, .i128_type => try o.intType(128, repr), + .usize_type, .isize_type => try o.intType(target.ptrBitWidth(), repr), + .c_char_type => try o.intType(target.cTypeBitSize(.char).?, repr), + .c_short_type => try o.intType(target.cTypeBitSize(.short).?, repr), + .c_ushort_type => try o.intType(target.cTypeBitSize(.ushort).?, repr), + .c_int_type => try o.intType(target.cTypeBitSize(.int).?, repr), + .c_uint_type => try o.intType(target.cTypeBitSize(.uint).?, repr), + .c_long_type => try o.intType(target.cTypeBitSize(.long).?, repr), + .c_ulong_type => try o.intType(target.cTypeBitSize(.ulong).?, repr), + .c_longlong_type => try o.intType(target.cTypeBitSize(.longlong).?, repr), + .c_ulonglong_type => try o.intType(target.cTypeBitSize(.ulonglong).?, repr), .c_longdouble_type, .f16_type, .f32_type, @@ -2909,11 +2925,44 @@ pub const Object = struct { .f80_type, .f128_type, => switch (t.floatBits(target)) { - 16 => if (backendSupportsF16(target)) .half else .i16, - 32 => .float, - 64 => .double, - 80 => if (backendSupportsF80(target)) .x86_fp80 else .i80, - 128 => .fp128, + 16 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .half, + .soft => .i16, + }, + 32 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .float, + .soft => .i32, + }, + 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .double, + .soft => .i64, + }, + 80 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .x86_fp80, + .soft => { + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f80_layout = try o.softF80Layout(.{ + .llvm_field_types_buf = &llvm_field_types_buf, + }); + return o.builder.structType( + .normal, + llvm_field_types_buf[0..f80_layout.llvm_fields_len], + ); + }, + }, + 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .fp128, + .soft => { + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f128_layout = try o.softF128Layout(.{ + .llvm_field_types_buf = &llvm_field_types_buf, + }); + return o.builder.structType( + .normal, + llvm_field_types_buf[0..f128_layout.llvm_fields_len], + ); + }, + }, else => unreachable, }, .anyopaque_type => { @@ -2972,10 +3021,7 @@ pub const Object = struct { .none, => unreachable, else => switch (ip.indexToKey(t.toIntern())) { - .int_type => |int_type| switch (repr) { - .by_value => try o.builder.intType(int_type.bits), - .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)), - }, + .int_type => |int_type| o.intType(int_type.bits, repr), .ptr_type => |ptr_type| type: { const ptr_ty = try o.builder.ptrType( toLlvmAddressSpace(ptr_type.flags.address_space, target), @@ -2992,11 +3038,13 @@ pub const Object = struct { array_type.lenIncludingSentinel(), try o.lowerType(.fromInterned(array_type.child), repr), ), - .vector_type => |vector_type| o.builder.vectorType( - .normal, - vector_type.len, - try o.lowerType(.fromInterned(vector_type.child), .by_value), - ), + .vector_type => |vector_type| if (isByRef(t, zcu)) { + const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), repr); + return o.builder.arrayType(vector_type.len, child_llvm_ty); + } else { + const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .as_value); + return o.builder.vectorType(.normal, vector_type.len, child_llvm_ty); + }, .opt_type => |child_ty| { // Must stay in sync with `opt_payload` logic in `lowerPtr`. switch (Type.fromInterned(child_ty).classify(zcu)) { @@ -3256,8 +3304,11 @@ pub const Object = struct { return ty; }, .opaque_type, .spirv_type => unreachable, // no runtime bits - .enum_type => try o.lowerType(t.backingIntType(zcu), repr), - .func_type => |func_type| try o.lowerFnType(t, func_type), + .enum_type => try o.intType(t.backingIntType(zcu).intInfo(zcu).bits, repr), + .func_type => |func_type| { + assert(t.fnHasRuntimeBits(zcu)); + return o.lowerFnType(.fromIntern(func_type, ip)); + }, .error_set_type, .inferred_error_set_type => try o.errorIntType(repr), // values, not types .undef, @@ -3283,14 +3334,28 @@ pub const Object = struct { }; } - fn lowerFnType(o: *Object, fn_ty: Type, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { + pub const FuncInfo = struct { + cc: std.lang.CallingConvention, + noalias_bits: u32 = 0, + param_types: []const InternPool.Index, + return_type: InternPool.Index = .void_type, + is_var_args: bool = false, + + pub fn fromIntern(fn_info: InternPool.Key.FuncType, ip: *InternPool) FuncInfo { + return .{ + .cc = fn_info.cc, + .noalias_bits = fn_info.noalias_bits, + .param_types = fn_info.param_types.get(ip), + .return_type = fn_info.return_type, + .is_var_args = fn_info.is_var_args, + }; + } + }; + pub fn lowerFnType(o: *Object, fn_info: FuncInfo) Allocator.Error!Builder.Type { const zcu = o.zcu; - const ip = &zcu.intern_pool; const target = zcu.getTarget(); - assert(fn_ty.fnHasRuntimeBits(zcu)); - - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); var llvm_params: std.ArrayList(Builder.Type) = .empty; defer llvm_params.deinit(o.gpa); @@ -3305,35 +3370,35 @@ pub const Object = struct { try llvm_params.append(o.gpa, llvm_ptr_ty); } - var it = iterateParamTypes(o, fn_info); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); while (try it.next()) |lowering| switch (lowering) { .no_bits => continue, .byval => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .by_value)); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); + try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .memory_access else .as_value)); }, .byref, .byref_mut => { try llvm_params.append(o.gpa, .ptr); }, .abi_sized_int => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); try llvm_params.append(o.gpa, try o.builder.intType( @intCast(param_ty.abiSize(zcu) * 8), )); }, .slice => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); try llvm_params.appendSlice(o.gpa, &.{ try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)), - try o.lowerType(.usize, .by_value), + try o.lowerType(.usize, .as_value), }); }, .multiple_llvm_types => { try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]); }, .float_array => |count| { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); + const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .memory_access); try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty)); }, .i32_array, .i64_array => |arr_len| { @@ -3347,7 +3412,7 @@ pub const Object = struct { const llvm_ret_ty: Builder.Type = switch (ret_strat) { .void, .sret => .void, - .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .by_value), + .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .as_value), .mem_cast => |llvm_ret_ty| llvm_ret_ty, }; const llvm_fn_kind: Builder.Type.Function.Kind = switch (fn_info.is_var_args) { @@ -3405,7 +3470,12 @@ pub const Object = struct { var bigint_space: Value.BigIntSpace = undefined; const bigint = val.toBigInt(&bigint_space, zcu); const llvm_int_ty = try o.lowerType(ty, repr); - return o.builder.bigIntConst(llvm_int_ty, bigint); + if (llvm_int_ty.isInteger(&o.builder)) + return o.builder.bigIntConst(llvm_int_ty, bigint); + const buffer = try o.gpa.alloc(u8, llvm_int_ty.aggregateLen(&o.builder)); + defer o.gpa.free(buffer); + bigint.writeTwosComplement(buffer, target.cpu.arch.endian()); + return o.builder.stringConst(try o.builder.string(buffer)); }, .err => |err| { const int = zcu.intern_pool.getErrorValueIfExists(err.name).?; @@ -3460,18 +3530,12 @@ pub const Object = struct { }, .enum_tag => |enum_tag| o.lowerValue(enum_tag.int, repr), .float => switch (ty.floatBits(target)) { - 16 => if (backendSupportsF16(target)) - try o.builder.halfConst(val.toFloat(f16, zcu)) - else - try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, zcu)))), - 32 => try o.builder.floatConst(val.toFloat(f32, zcu)), - 64 => try o.builder.doubleConst(val.toFloat(f64, zcu)), - 80 => if (backendSupportsF80(target)) - try o.builder.x86_fp80Const(val.toFloat(f80, zcu)) - else - try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, zcu)))), - 128 => try o.builder.fp128Const(val.toFloat(f128, zcu)), else => unreachable, + 16 => try o.f16Const(val.toFloat(f16, zcu)), + 32 => try o.f32Const(val.toFloat(f32, zcu)), + 64 => try o.f64Const(val.toFloat(f64, zcu)), + 80 => try o.f80Const(val.toFloat(f80, zcu)), + 128 => try o.f128Const(val.toFloat(f128, zcu)), }, .ptr => try o.lowerPtr(arg_val, 0), .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{ @@ -3590,12 +3654,13 @@ pub const Object = struct { }, .vector_type => |vector_type| { const vector_ty = try o.lowerType(ty, repr); + const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; + var bfa_buf: ExpectedContents = undefined; + var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa); + const allocator = bfa.allocator(); + const is_by_ref = isByRef(ty, zcu); switch (aggregate.storage) { .bytes, .elems => { - const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; - var bfa_buf: ExpectedContents = undefined; - var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa); - const allocator = bfa.allocator(); const vals = try allocator.alloc(Builder.Constant, vector_type.len); defer allocator.free(vals); @@ -3604,16 +3669,21 @@ pub const Object = struct { result_val.* = try o.builder.intConst(.i8, byte); }, .elems => |elems| for (vals, elems) |*result_val, elem| { - result_val.* = try o.lowerValue(elem, .by_value); + result_val.* = try o.lowerValue(elem, if (is_by_ref) repr else .as_value); }, .repeated_elem => unreachable, } - return o.builder.vectorConst(vector_ty, vals); + return if (is_by_ref) + o.builder.arrayConst(vector_ty, vals) + else + o.builder.vectorConst(vector_ty, vals); }, - .repeated_elem => |elem| return o.builder.splatConst( - vector_ty, - try o.lowerValue(elem, .by_value), - ), + .repeated_elem => |elem| if (is_by_ref) { + const vals = try allocator.alloc(Builder.Constant, vector_type.len); + defer allocator.free(vals); + @memset(vals, try o.lowerValue(elem, repr)); + return o.builder.arrayConst(vector_ty, vals); + } else return o.builder.splatConst(vector_ty, try o.lowerValue(elem, .as_value)), } }, .tuple_type => |tuple| { @@ -3841,6 +3911,117 @@ pub const Object = struct { }; } + pub fn f16Const(o: *Object, val: f16) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 16)) { + .hard => o.builder.halfConst(val), + .soft => o.builder.intConst(.i16, @as(u16, @bitCast(val))), + }; + } + + pub fn f32Const(o: *Object, val: f32) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 32)) { + .hard => o.builder.floatConst(val), + .soft => o.builder.intConst(.i32, @as(u32, @bitCast(val))), + }; + } + + pub fn f64Const(o: *Object, val: f64) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 64)) { + .hard => o.builder.doubleConst(val), + .soft => o.builder.intConst(.i64, @as(u64, @bitCast(val))), + }; + } + + pub fn f80Const(o: *Object, val: f80) Allocator.Error!Builder.Constant { + switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 80)) { + .hard => return o.builder.x86_fp80Const(val), + .soft => {}, + } + var llvm_field_tags_buf: [5]SoftF80Layout.LlvmFieldTag = undefined; + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f80_layout = try o.softF80Layout(.{ + .llvm_field_tags_buf = &llvm_field_tags_buf, + .llvm_field_types_buf = &llvm_field_types_buf, + }); + const llvm_field_types = llvm_field_types_buf[0..f80_layout.llvm_fields_len]; + const f80_llvm_ty = try o.builder.structType(.normal, llvm_field_types); + const f80_repr: packed struct { mantissa: u64, exponent: u16 } = @bitCast(val); + var llvm_field_vals_buf: [5]Builder.Constant = undefined; + const llvm_field_vals = llvm_field_vals_buf[0..f80_layout.llvm_fields_len]; + for ( + llvm_field_vals, + llvm_field_tags_buf[0..f80_layout.llvm_fields_len], + llvm_field_types, + ) |*llvm_field_val, llvm_field_tag, llvm_field_type| + llvm_field_val.* = switch (llvm_field_tag) { + .mantissa => try o.builder.intConst(llvm_field_type, f80_repr.mantissa), + .exponent => try o.builder.intConst(llvm_field_type, f80_repr.exponent), + .padding => try o.builder.undefConst(llvm_field_type), + }; + return o.builder.structConst(f80_llvm_ty, llvm_field_vals); + } + + pub fn f128Const(o: *Object, val: f128) Allocator.Error!Builder.Constant { + switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 128)) { + .hard => return o.builder.fp128Const(val), + .soft => {}, + } + var llvm_field_tags_buf: [5]SoftF128Layout.LlvmFieldTag = undefined; + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f128_layout = try o.softF128Layout(.{ + .llvm_field_tags_buf = &llvm_field_tags_buf, + .llvm_field_types_buf = &llvm_field_types_buf, + }); + const llvm_field_types = llvm_field_types_buf[0..f128_layout.llvm_fields_len]; + const f128_llvm_ty = try o.builder.structType(.normal, llvm_field_types); + const f128_repr: packed struct { lo: u64, hi: u64 } = @bitCast(val); + var llvm_field_vals_buf: [5]Builder.Constant = undefined; + const llvm_field_vals = llvm_field_vals_buf[0..f128_layout.llvm_fields_len]; + for ( + llvm_field_vals, + llvm_field_tags_buf[0..f128_layout.llvm_fields_len], + llvm_field_types, + ) |*llvm_field_val, llvm_field_tag, llvm_field_type| + llvm_field_val.* = switch (llvm_field_tag) { + .lo => try o.builder.intConst(llvm_field_type, f128_repr.lo), + .hi => try o.builder.intConst(llvm_field_type, f128_repr.hi), + .padding => try o.builder.undefConst(llvm_field_type), + }; + return o.builder.structConst(f128_llvm_ty, llvm_field_vals); + } + + pub fn lowerConstRef( + o: *Object, + constant: Builder.Constant, + @"align": Builder.Alignment, + ) Allocator.Error!Builder.Constant { + assert(@"align" != .default); + const zcu = o.zcu; + const gpa = zcu.comp.gpa; + const gop = try o.const_map.getOrPut(gpa, constant); + if (gop.found_existing) { + // Keep the greater of the two alignments. + const llvm_variable = gop.value_ptr.*; + const llvm_old_align = llvm_variable.getAlignment(&o.builder); + const llvm_new_align = llvm_old_align.max(@"align"); + llvm_variable.setAlignment(llvm_new_align, &o.builder); + return llvm_variable.ptrConst(&o.builder).global.toConst(); + } + errdefer assert(o.const_map.remove(constant)); + + const llvm_ty = constant.typeOf(&o.builder); + const llvm_addrspace = toLlvmAddressSpace(.generic, zcu.getTarget()); + const llvm_variable = try o.builder.addVariable(.empty, llvm_ty, llvm_addrspace); + gop.value_ptr.* = llvm_variable; + try llvm_variable.setInitializer(constant, &o.builder); + llvm_variable.setMutability(.constant, &o.builder); + llvm_variable.setAlignment(@"align", &o.builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); + return llvm_global.toConst(); + } + fn lowerPtr( o: *Object, ptr_val: InternPool.Index, @@ -3860,7 +4041,7 @@ pub const Object = struct { const orig_ptr_ty: Type = .fromInterned(uav.orig_ty); const base_ptr = try o.lowerUavRef( uav.val, - orig_ptr_ty.ptrAlignment(zcu), + orig_ptr_ty.ptrAlignment(zcu).toLlvm(), orig_ptr_ty.ptrAddressSpace(zcu), ); return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{ @@ -3869,8 +4050,8 @@ pub const Object = struct { }, .int => try o.builder.castConst( .inttoptr, - try o.builder.intConst(try o.lowerType(.usize, .by_value), offset), - try o.lowerType(.fromInterned(ptr.ty), .by_value), + try o.builder.intConst(try o.lowerType(.usize, .as_value), offset), + try o.lowerType(.fromInterned(ptr.ty), .as_value), ), .eu_payload => |eu_ptr| try o.lowerPtr( eu_ptr, @@ -3912,12 +4093,12 @@ pub const Object = struct { pub fn lowerPtrToVoid( o: *Object, - /// Must not be `.none`. - @"align": InternPool.Alignment, + /// Must not be `.default`. + @"align": Builder.Alignment, @"addrspace": std.lang.AddressSpace, ) Allocator.Error!Builder.Constant { const addr: u64 = @"align".toByteUnits().?; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const llvm_addr = try o.builder.intConst(llvm_usize, addr); const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", o.zcu.getTarget())); return o.builder.castConst(.inttoptr, llvm_addr, llvm_ptr_ty); @@ -3926,11 +4107,11 @@ pub const Object = struct { pub fn lowerUavRef( o: *Object, uav_val: InternPool.Index, - /// Must not be `.none`. - @"align": InternPool.Alignment, + /// Must not be `.default`. + @"align": Builder.Alignment, @"addrspace": std.lang.AddressSpace, ) Allocator.Error!Builder.Constant { - assert(@"align" != .none); + assert(@"align" != .default); const zcu = o.zcu; const ip = &zcu.intern_pool; @@ -3955,19 +4136,18 @@ pub const Object = struct { // Keep the greater of the two alignments. const llvm_variable = gop.value_ptr.*; const llvm_old_align = llvm_variable.getAlignment(&o.builder); - const llvm_new_align = llvm_old_align.max(@"align".toLlvm()); + const llvm_new_align = llvm_old_align.max(@"align"); llvm_variable.setAlignment(llvm_new_align, &o.builder); return llvm_variable.ptrConst(&o.builder).global.toConst(); } errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" })); - const llvm_ty = try o.lowerType(uav_ty, .in_memory); const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@backingInt(uav_val)}); - const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace); + const llvm_variable = try o.builder.addVariable(llvm_name, .void, llvm_addrspace); gop.value_ptr.* = llvm_variable; try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder); llvm_variable.setMutability(.constant, &o.builder); - llvm_variable.setAlignment(@"align".toLlvm(), &o.builder); + llvm_variable.setAlignment(@"align", &o.builder); const llvm_global = llvm_variable.ptrConst(&o.builder).global; llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); @@ -3986,7 +4166,7 @@ pub const Object = struct { .none => nav_ty.abiAlignment(zcu), else => |a| a, }; - return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace"); + return o.lowerPtrToVoid(nav_align.toLlvm(), nav.resolved.?.@"addrspace"); } const gop = try o.nav_map.getOrPut(gpa, nav_id); @@ -4015,7 +4195,7 @@ pub const Object = struct { attributes: *Builder.FunctionAttributes.Wip, param_ty: Type, param_index: u32, - fn_info: InternPool.Key.FuncType, + fn_info: FuncInfo, llvm_arg_i: u32, ) Allocator.Error!void { const zcu = o.zcu; @@ -4055,19 +4235,26 @@ pub const Object = struct { }; } + pub const Byval = struct { alignment: InternPool.Alignment = .none }; pub fn addByRefParamAttrs( o: *Object, attributes: *Builder.FunctionAttributes.Wip, llvm_arg_i: u32, - byval: bool, + maybe_byval: ?Byval, param_ty: Type, ) Allocator.Error!void { const llvm_param_ty = try o.lowerType(param_ty, .in_memory); - const alignment = param_ty.abiAlignment(o.zcu).toLlvm(); - try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); - try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(alignment) }, &o.builder); - if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder); + try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); + try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); + const alignment = if (maybe_byval) |byval| alignment: { + try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder); + break :alignment byval.alignment; + } else .none; + try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(switch (alignment) { + .none => param_ty.abiAlignment(o.zcu), + else => alignment, + }.toLlvm()) }, &o.builder); } pub fn getErrorNameTable(o: *Object) Allocator.Error!Builder.Variable.Index { @@ -4075,18 +4262,18 @@ pub const Object = struct { const name = try o.builder.strtabString("__zig_error_name_table"); // TODO: Address space - const variable_index = try o.builder.addVariable(name, .ptr, .default); - variable_index.setMutability(.constant, &o.builder); - variable_index.setAlignment( + const llvm_variable = try o.builder.addVariable(name, .ptr, .default); + llvm_variable.setMutability(.constant, &o.builder); + llvm_variable.setAlignment( Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(), &o.builder, ); - const global_index = variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, &o.builder); - global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); - o.error_name_table = variable_index; - return variable_index; + o.error_name_table = llvm_variable; + return llvm_variable; } pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index { @@ -4094,13 +4281,13 @@ pub const Object = struct { if (o.errors_len_variable == .none) { const llvm_err_int_ty = try o.errorIntType(.in_memory); const name = try builder.strtabString("__zig_errors_len"); - const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default); - variable_index.setMutability(.constant, builder); - variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); - const global_index = variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, builder); - global_index.setUnnamedAddr(.unnamed_addr, builder); - o.errors_len_variable = variable_index; + const llvm_variable = try builder.addVariable(name, llvm_err_int_ty, .default); + llvm_variable.setMutability(.constant, builder); + llvm_variable.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, builder); + llvm_global.setUnnamedAddr(.unnamed_addr, builder); + o.errors_len_variable = llvm_variable; } return o.errors_len_variable; } @@ -4112,43 +4299,43 @@ pub const Object = struct { const gop = try o.enum_tag_name_map.getOrPut(o.gpa, enum_ty.toIntern()); if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.enum_tag_name_map.remove(enum_ty.toIntern())); - const function_index = try o.builder.addFunction( + const llvm_function = try o.builder.addFunction( // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type. // TODO: change the builder API so we don't need to do this. try o.builder.fnType(.void, &.{}, .normal), try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}), toLlvmAddressSpace(.generic, zcu.getTarget()), ); - gop.value_ptr.* = function_index; - try o.updateEnumTagNameFunction(enum_ty, function_index); - return function_index; + gop.value_ptr.* = llvm_function; + try o.updateEnumTagNameFunction(enum_ty, llvm_function); + return llvm_function; } fn updateEnumTagNameFunction( o: *Object, enum_ty: Type, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, ) Allocator.Error!void { const zcu = o.zcu; const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); - const llvm_usize_ty = try o.lowerType(.usize, .by_value); - const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .by_value); - const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); + const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .as_value); + const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value); - function_index.ptrConst(&o.builder).global.ptr(&o.builder).type = + llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type = try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer); - function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); + llvm_function.setCallConv(.fastcc, &o.builder); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); var wip = try Builder.WipFunction.init(&o.builder, .{ - .function = function_index, + .function = llvm_function, .strip = true, }); defer wip.deinit(); @@ -4167,23 +4354,23 @@ pub const Object = struct { for (0..loaded_enum.field_names.len) |field_index| { const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); const name_init = try o.builder.stringConst(name); - const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); - try name_variable_index.setInitializer(name_init, &o.builder); - name_variable_index.setMutability(.constant, &o.builder); - name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); - const name_global_index = name_variable_index.ptrConst(&o.builder).global; - name_global_index.setLinkage(.private, &o.builder); - name_global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); + try name_llvm_variable.setInitializer(name_init, &o.builder); + name_llvm_variable.setMutability(.constant, &o.builder); + name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); + const name_llvm_global = name_llvm_variable.ptrConst(&o.builder).global; + name_llvm_global.setLinkage(.private, &o.builder); + name_llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); const name_val = try o.builder.structValue(llvm_ret_ty, &.{ - name_global_index.toConst(), + name_llvm_global.toConst(), try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1), }); const return_block = try wip.block(1, "Name"); const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, field_index)) { .none => try o.builder.intConst(llvm_int_ty, field_index), // auto-numbered - else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .as_value), }; try wip_switch.addCase(llvm_tag_val, return_block, &wip); @@ -4209,40 +4396,40 @@ pub const Object = struct { const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern()); if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.named_enum_map.remove(enum_ty.toIntern())); - const function_index = try o.builder.addFunction( + const llvm_function = try o.builder.addFunction( // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type. // TODO: change the builder API so we don't need to do this. try o.builder.fnType(.void, &.{}, .normal), try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}), toLlvmAddressSpace(.generic, zcu.getTarget()), ); - gop.value_ptr.* = function_index; - try o.updateIsNamedEnumValueFunction(enum_ty, function_index); - return function_index; + gop.value_ptr.* = llvm_function; + try o.updateIsNamedEnumValueFunction(enum_ty, llvm_function); + return llvm_function; } fn updateIsNamedEnumValueFunction( o: *Object, enum_ty: Type, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, ) Allocator.Error!void { const zcu = o.zcu; const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); - const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .by_value); - function_index.ptrConst(&o.builder).global.ptr(&o.builder).type = + const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value); + llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type = try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer); - function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); + llvm_function.setCallConv(.fastcc, &o.builder); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); var wip: Builder.WipFunction = try .init(&o.builder, .{ - .function = function_index, + .function = llvm_function, .strip = true, }); defer wip.deinit(); @@ -4256,7 +4443,7 @@ pub const Object = struct { if (loaded_enum.field_values.len > 0) { for (loaded_enum.field_values.get(ip)) |tag_val_ip| { - const llvm_tag_val = try o.lowerValue(tag_val_ip, .by_value); + const llvm_tag_val = try o.lowerValue(tag_val_ip, .as_value); try wip_switch.addCase(llvm_tag_val, named_block, &wip); } } else { @@ -4278,20 +4465,27 @@ pub const Object = struct { pub fn getLibcFunction( o: *Object, + pt: Zcu.PerThread, fn_name: Builder.StrtabString, - param_types: []const Builder.Type, - return_type: Builder.Type, + fn_info: FuncInfo, ) Allocator.Error!Builder.Function.Index { if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) { .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function, .function => |function| function, .variable, .replaced => unreachable, }; - return o.builder.addFunction( - try o.builder.fnType(return_type, param_types, .normal), + const llvm_function = try o.builder.addFunction( + try o.lowerFnType(fn_info), fn_name, toLlvmAddressSpace(.generic, o.zcu.getTarget()), ); + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{ + .name = fn_name.slice(&o.builder).?, + }, fn_info); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); + return llvm_function; } }; @@ -4328,7 +4522,7 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) std.lang.CallingConvention.SpirvFragmentOptions, std.lang.CallingConvention.SpirvMeshOptions, => .{ null, 0, 0 }, - else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), + else => @compileError("TODO: toLlvmCallConv(." ++ @tagName(pl) ++ ")"), }, }; return .{ @@ -4411,6 +4605,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const .x86_16_interrupt, .x86_sysv, .x86_win, + .x86_mingw, .x86_thiscall_mingw, .x86_64_x32, .aarch64_aapcs, @@ -4585,47 +4780,6 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.lang.AddressSpace, target: }; } -/// This function returns true if we expect LLVM to lower f16 correctly -/// and false if we expect LLVM to crash if it encounters an f16 type, -/// or if it produces miscompilations. -pub fn backendSupportsF16(target: *const std.Target) bool { - return switch (target.cpu.arch) { - .arm, - .armeb, - .thumb, - .thumbeb, - => target.abi.float() == .soft or target.cpu.has(.arm, .fullfp16), - else => true, - }; -} - -/// This function returns true if we expect LLVM to lower x86_fp80 correctly -/// and false if we expect LLVM to crash if it encounters an x86_fp80 type, -/// or if it produces miscompilations. -pub fn backendSupportsF80(target: *const std.Target) bool { - return switch (target.cpu.arch) { - .x86, .x86_64 => !target.cpu.has(.x86, .soft_float), - else => false, - }; -} - -/// This function returns true if we expect LLVM to lower f128 correctly, -/// and false if we expect LLVM to crash if it encounters an f128 type, -/// or if it produces miscompilations. -pub fn backendSupportsF128(target: *const std.Target) bool { - return switch (target.cpu.arch) { - // https://github.com/llvm/llvm-project/issues/121122 - .amdgcn, - => false, - .arm, - .armeb, - .thumb, - .thumbeb, - => target.abi.float() == .soft or target.cpu.has(.arm, .fp_armv8), - else => true, - }; -} - /// We need to insert extra padding if LLVM's isn't enough. /// However we don't want to ever call LLVMABIAlignmentOfType or /// LLVMABISizeOfType because these functions will trip assertions diff --git a/src/codegen/llvm/FuncGen.zig b/src/codegen/llvm/FuncGen.zig index 6e2d71994a6f67a10a9aa7723071c419cd1815e4..2bdd059f1fe217c8675e5faa9acead19208c2cf3 100644 --- a/src/codegen/llvm/FuncGen.zig +++ b/src/codegen/llvm/FuncGen.zig @@ -164,12 +164,12 @@ fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant { const zcu = o.zcu; const ty = val.typeOf(zcu); if (!isByRef(ty, zcu)) { - return o.lowerValue(val.toIntern(), .by_value); + return o.lowerValue(val.toIntern(), .as_value); } else { // We need a pointer to a global constant, i.e. a UAV. return o.lowerUavRef( val.toIntern(), - ty.abiAlignment(zcu), + ty.abiAlignment(zcu).toLlvm(), target_util.defaultAddressSpace(zcu.getTarget(), .global_constant), ); } @@ -190,10 +190,10 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { const fn_info = zcu.typeToFunc(fn_ty).?; const param_types = fn_info.param_types.get(ip); - var it = iterateParamTypes(o, fn_info); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types.get(ip)); // Populate `fg.ret_ptr`... - fg.ret_ptr = switch (try fnReturnStrat(o, fn_info)) { + fg.ret_ptr = switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) { .sret => rp: { defer it.llvm_index += 1; break :rp fg.wip.arg(it.llvm_index); @@ -218,7 +218,7 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { switch (lowering) { .no_bits => continue, .byval => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_index = it.zig_index - 1; const param_ty: Type = .fromInterned(param_types[param_index]); const param = fg.wip.arg(it.llvm_index - 1); @@ -237,15 +237,16 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { .byref, .byref_mut => { const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param = fg.wip.arg(it.llvm_index - 1); + const alignment = if (it.byval_attr) |byval_attr| byval_attr.alignment else .none; - if (isByRef(param_ty, zcu)) { + if (alignment == .none and isByRef(param_ty, zcu)) { args.appendAssumeCapacity(param); } else { - args.appendAssumeCapacity(try fg.load(param, .none, param_ty, .normal)); + args.appendAssumeCapacity(try fg.load(param, alignment, param_ty, .normal)); } }, .abi_sized_int => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param = fg.wip.arg(it.llvm_index - 1); @@ -260,18 +261,18 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { } }, .slice => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); assert(!isByRef(param_ty, zcu)); const slice_val = try fg.wip.buildAggregate( - try o.lowerType(param_ty, .by_value), + try o.lowerType(param_ty, .as_value), &.{ fg.wip.arg(it.llvm_index - 2), fg.wip.arg(it.llvm_index - 1) }, "", ); args.appendAssumeCapacity(slice_val); }, .multiple_llvm_types => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param_alignment = param_ty.abiAlignment(zcu); const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); @@ -721,29 +722,19 @@ fn genBodyDebugScope( try self.genBody(body, coverage_point); } -const CallAttr = enum { - Auto, - NeverTail, - NeverInline, - AlwaysTail, - AlwaysInline, -}; - -fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value { - const air_call = self.air.unwrapCall(inst); +fn airCall(fg: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value { + const o = fg.object; + const zcu = o.zcu; + const air_call = fg.air.unwrapCall(inst); const args = air_call.args; - const o = self.object; - const pt = self.pt; - const zcu = o.zcu; const ip = &zcu.intern_pool; - const callee_ty = self.typeOf(air_call.callee); + const callee_ty = fg.typeOf(air_call.callee); const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) { .@"fn" => callee_ty, .pointer => callee_ty.childType(zcu), else => unreachable, }; const fn_info = zcu.typeToFunc(zig_fn_ty).?; - const return_type: Type = .fromInterned(fn_info.return_type); const llvm_fn = llvm_fn: { // If the callee is a function *body*, we need to use a pointer to the global. if (air_call.callee.toInterned()) |ip_index| switch (ip.indexToKey(ip_index)) { @@ -752,22 +743,54 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier else => {}, }; // Otherwise, the operand is already a function pointer (possibly runtime-known). - break :llvm_fn try self.resolveInst(air_call.callee); + break :llvm_fn try fg.resolveInst(air_call.callee); }; + + const arg_types = try fg.gpa.alloc(InternPool.Index, args.len); + defer fg.gpa.free(arg_types); + const arg_values = try fg.gpa.alloc(Builder.Value, args.len); + defer fg.gpa.free(arg_values); + for (arg_types, arg_values, args) |*arg_type, *arg_value, arg| { + const arg_ty = fg.typeOf(arg); + arg_type.* = arg_ty.toIntern(); + arg_value.* = if (arg_ty.hasRuntimeBits(zcu)) try fg.resolveInst(arg) else .none; + } + return fg.buildCall(.{ + .is_unused = fg.liveness.isUnused(inst), + .modifier = modifier, + }, try o.lowerType(zig_fn_ty, .as_value), llvm_fn, .fromIntern(fn_info, ip), arg_types, arg_values); +} + +fn buildCall( + fg: *FuncGen, + opts: struct { + is_unused: bool = false, + modifier: std.lang.CallModifier = .auto, + }, + llvm_fn_ty: Builder.Type, + llvm_fn: Builder.Value, + fn_info: Object.FuncInfo, + arg_types: []const InternPool.Index, + arg_values: []const Builder.Value, +) Allocator.Error!Builder.Value { + const o = fg.object; + const pt = fg.pt; + const zcu = o.zcu; + const return_type: Type = .fromInterned(fn_info.return_type); const target = zcu.getTarget(); - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); - var llvm_args = std.array_list.Managed(Builder.Value).init(self.gpa); - defer llvm_args.deinit(); + var llvm_args: std.ArrayList(Builder.Value) = .empty; + defer llvm_args.deinit(fg.gpa); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); - if (self.disable_intrinsics) { + if (fg.disable_intrinsics) { try attributes.addFnAttr(.nobuiltin, &o.builder); } - switch (modifier) { + switch (opts.modifier) { .auto, .always_tail => {}, .never_tail, .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder), .no_suspend, .always_inline, .compile_time => unreachable, @@ -775,10 +798,11 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const sret_alloc: ?Builder.Value = switch (ret_strat) { .sret => sret_alloc: { - try attributes.addParamAttr(0, .{ .sret = try o.lowerType(return_type, .in_memory) }, &o.builder); + const alignment = return_type.abiAlignment(zcu).toLlvm(); + try o.addSRetFnAttributes(&attributes, try o.lowerType(return_type, .in_memory), alignment, .callsite); - const ptr = try self.buildZigAlloca(return_type, .none); - try llvm_args.append(ptr); + const ptr = try fg.buildZigAlloca(return_type, .none); + try llvm_args.append(fg.gpa, ptr); break :sret_alloc ptr; }, else => sret_alloc: { @@ -792,132 +816,111 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; if (err_return_tracing) { - assert(self.err_ret_trace != .none); - try llvm_args.append(self.err_ret_trace); + assert(fg.err_ret_trace != .none); + try llvm_args.append(fg.gpa, fg.err_ret_trace); } - var it = iterateParamTypes(o, fn_info); - while (try it.nextCall(self, args)) |lowering| switch (lowering) { - .no_bits => continue, - .byval => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - if (isByRef(param_ty, zcu)) { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - // We don't need to handle non-ABI-sized integer types in memory here since they are - // never by-ref. - const llvm_param_ty = try o.lowerType(param_ty, .in_memory); - const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, ""); - try llvm_args.append(loaded); - } else { - try llvm_args.append(llvm_arg); - } - }, - .byref => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - if (isByRef(param_ty, zcu)) { - try llvm_args.append(llvm_arg); - } else { - const arg_ptr = try self.buildZigAlloca(param_ty, .none); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); - try llvm_args.append(arg_ptr); - } - }, - .byref_mut => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); + while (try it.nextCall(arg_types)) |lowering| { + const arg_ty: Type = .fromInterned(arg_types[it.zig_index - 1]); + const arg_val = arg_values[it.zig_index - 1]; + switch (lowering) { + .no_bits => continue, + .byval => { + if (isByRef(arg_ty, zcu)) { + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + // We don't need to handle non-ABI-sized integer types in memory here since they are + // never by-ref. + const llvm_arg_ty = try o.lowerType(arg_ty, .memory_access); + const loaded = try fg.wip.load(.normal, llvm_arg_ty, arg_val, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } else { + try llvm_args.append(fg.gpa, arg_val); + } + }, + .byref => { + if (isByRef(arg_ty, zcu)) { + try llvm_args.append(fg.gpa, arg_val); + } else { + const arg_ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); + try llvm_args.append(fg.gpa, arg_ptr); + } + }, + .byref_mut => { + const arg_ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); + try llvm_args.append(fg.gpa, arg_ptr); + }, + .abi_sized_int => { + const int_llvm_ty = try o.builder.intType(@intCast(arg_ty.abiSize(zcu) * 8)); - const arg_ptr = try self.buildZigAlloca(param_ty, .none); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); - try llvm_args.append(arg_ptr); - }, - .abi_sized_int => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(zcu) * 8)); + if (isByRef(arg_ty, zcu)) { + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + const loaded = try fg.wip.load(.normal, int_llvm_ty, arg_val, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } else { + // LLVM does not allow bitcasting structs so we must allocate + // a local, store as one type, and then load as another type. + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + const ptr = try fg.buildAlloca(int_llvm_ty, alignment); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + const loaded = try fg.wip.load(.normal, int_llvm_ty, ptr, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } + }, + .slice => { + const ptr = try fg.wip.extractValue(arg_val, &.{0}, ""); + const len = try fg.wip.extractValue(arg_val, &.{1}, ""); + try llvm_args.appendSlice(fg.gpa, &.{ ptr, len }); + }, + .multiple_llvm_types => { + const arg_alignment = arg_ty.abiAlignment(zcu); + const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); + const arg_ptr = try fg.buildAlloca(llvm_ty, arg_alignment.toLlvm()); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); - if (isByRef(param_ty, zcu)) { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, ""); - try llvm_args.append(loaded); - } else { - // LLVM does not allow bitcasting structs so we must allocate - // a local, store as one type, and then load as another type. - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const ptr = try self.buildAlloca(int_llvm_ty, alignment); - try self.store(ptr, .none, llvm_arg, param_ty, .normal); - const loaded = try self.wip.load(.normal, int_llvm_ty, ptr, alignment, ""); - try llvm_args.append(loaded); - } - }, - .slice => { - const arg = args[it.zig_index - 1]; - const llvm_arg = try self.resolveInst(arg); - const ptr = try self.wip.extractValue(llvm_arg, &.{0}, ""); - const len = try self.wip.extractValue(llvm_arg, &.{1}, ""); - try llvm_args.appendSlice(&.{ ptr, len }); - }, - .multiple_llvm_types => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - const param_alignment = param_ty.abiAlignment(zcu); - const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); - const arg_ptr = try self.buildAlloca(llvm_ty, param_alignment.toLlvm()); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); + try llvm_args.ensureUnusedCapacity(fg.gpa, it.types_len); + for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| { + const field_ptr = try fg.ptraddConst(arg_ptr, offset); + const loaded = try fg.wip.load(.normal, field_ty, field_ptr, arg_alignment.offset(offset).toLlvm(), ""); + llvm_args.appendAssumeCapacity(loaded); + } + }, + .float_array => |count| { + const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { + const ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + break :ptr ptr; + } else arg_val; - try llvm_args.ensureUnusedCapacity(it.types_len); - for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| { - const field_ptr = try self.ptraddConst(arg_ptr, offset); - const loaded = try self.wip.load(.normal, field_ty, field_ptr, param_alignment.offset(offset).toLlvm(), ""); - llvm_args.appendAssumeCapacity(loaded); - } - }, - .float_array => |count| { - const arg = args[it.zig_index - 1]; - const arg_ty = self.typeOf(arg); - const arg_val = try self.resolveInst(arg); + const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .memory_access); + const array_ty = try o.builder.arrayType(count, float_ty); - const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { - const ptr = try self.buildZigAlloca(arg_ty, .none); - try self.store(ptr, .none, arg_val, arg_ty, .normal); - break :ptr ptr; - } else arg_val; + const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); + try llvm_args.append(fg.gpa, loaded); + }, + .i32_array, .i64_array => |arr_len| { + const elem_size: u8 = if (lowering == .i32_array) 32 else 64; - const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .in_memory); - const array_ty = try o.builder.arrayType(count, float_ty); + const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { + const ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + break :ptr ptr; + } else arg_val; - const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); - try llvm_args.append(loaded); - }, - .i32_array, .i64_array => |arr_len| { - const elem_size: u8 = if (lowering == .i32_array) 32 else 64; - const arg = args[it.zig_index - 1]; - const arg_ty = self.typeOf(arg); - const arg_val = try self.resolveInst(arg); - - const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { - const ptr = try self.buildZigAlloca(arg_ty, .none); - try self.store(ptr, .none, arg_val, arg_ty, .normal); - break :ptr ptr; - } else arg_val; - - const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size))); - const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); - try llvm_args.append(loaded); - }, - }; + const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size))); + const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); + try llvm_args.append(fg.gpa, loaded); + }, + } + } const cc_info = llvm.toLlvmCallConv(fn_info.cc, target).?; { // Add argument attributes. - it = iterateParamTypes(o, fn_info); + it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); it.llvm_index += @intFromBool(ret_strat == .sret); it.llvm_index += @intFromBool(err_return_tracing); var remaining_inreg_int = cc_info.inreg_int_params; @@ -925,7 +928,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier while (try it.next()) |lowering| switch (lowering) { .byval => { const param_index = it.zig_index - 1; - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty = Type.fromInterned(fn_info.param_types[param_index]); if (!isByRef(param_ty, zcu)) { try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); } @@ -947,7 +950,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }, .byref => { const param_index = it.zig_index - 1; - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty: Type = .fromInterned(fn_info.param_types[param_index]); try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty); }, .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), @@ -961,8 +964,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier => continue, .slice => { - assert(!it.byval_attr); - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + assert(it.byval_attr == null); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); const ptr_info = param_ty.ptrInfo(zcu); const llvm_arg_i = it.llvm_index - 2; @@ -989,8 +992,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }; } - const call = try self.wip.call( - switch (modifier) { + const call = try fg.wip.call( + switch (opts.modifier) { .auto, .never_inline => .normal, .never_tail => .notail, .always_tail => .musttail, @@ -998,19 +1001,14 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }, cc_info.llvm_cc, try attributes.finish(&o.builder), - try o.lowerType(zig_fn_ty, .by_value), + llvm_fn_ty, llvm_fn, llvm_args.items, "", ); - if (fn_info.return_type == .noreturn_type and modifier != .always_tail) { - return .none; - } - - if (self.liveness.isUnused(inst)) { - return .none; - } + if (opts.is_unused) return .none; + if (fn_info.return_type == .noreturn_type and opts.modifier != .always_tail) return .none; // We exit this `switch` if we have a pointer to the return value. const ret_val_ptr: Builder.Value = switch (ret_strat) { @@ -1020,15 +1018,15 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier .sret => sret_alloc.?, .mem_cast => |llvm_ret_ty| ret_val_ptr: { const alignment = return_type.abiAlignment(zcu).toLlvm(); - const ptr = try self.buildAlloca(llvm_ret_ty, alignment); - _ = try self.wip.store(.normal, call, ptr, alignment); + const ptr = try fg.buildAlloca(llvm_ret_ty, alignment); + _ = try fg.wip.store(.normal, call, ptr, alignment); break :ret_val_ptr ptr; }, }; if (isByRef(return_type, zcu)) { return ret_val_ptr; } else { - return self.load(ret_val_ptr, .none, return_type, .normal); + return fg.load(ret_val_ptr, .none, return_type, .normal); } } @@ -1038,7 +1036,7 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v const target = zcu.getTarget(); const panic_func = zcu.funcInfo(zcu.std_lang_decl_values.get(panic_id.toStdLangDecl())); const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?; - const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty), .by_value); + const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty), .as_value); const llvm_panic_fn_ref = try o.lowerNavRef(panic_func.owner_nav); @@ -1067,7 +1065,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false; const ret_ty_align = ret_ty.abiAlignment(zcu); @@ -1076,7 +1074,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo .none => try self.buildZigAlloca(ret_ty, .none), else => |rp| rp, }; - const len = try o.builder.intValue(try o.lowerType(.usize, .by_value), ret_ty.abiSize(zcu)); + const len = try o.builder.intValue(try o.lowerType(.usize, .as_value), ret_ty.abiSize(zcu)); _ = try self.wip.callMemSet( rp, ret_ty_align.toLlvm(), @@ -1141,7 +1139,7 @@ fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void { const ret_ty = ptr_ty.childType(zcu); const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; const ptr = try self.resolveInst(un_op); - switch (try fnReturnStrat(o, fn_info)) { + switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) { .void => _ = try self.wip.retVoid(), .sret => { assert(self.ret_ptr != .none); @@ -1165,7 +1163,7 @@ fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const list = try self.resolveInst(ty_op.operand); const arg_ty = ty_op.ty.toType(); - const llvm_arg_ty = try self.object.lowerType(arg_ty, .by_value); + const llvm_arg_ty = try self.object.lowerType(arg_ty, .as_value); return self.wip.vaArg(list, llvm_arg_ty, ""); } @@ -1378,7 +1376,7 @@ fn lowerBlock( if (have_block_result) { const llvm_ty: Builder.Type = switch (isByRef(inst_ty, zcu)) { true => .ptr, - false => try o.lowerType(inst_ty, .by_value), + false => try o.lowerType(inst_ty, .as_value), }; parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len); const phi = try self.wip.phi(llvm_ty, ""); @@ -1485,7 +1483,7 @@ fn lowerSwitchDispatch( const table_index = try self.wip.conv( .unsigned, try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""), - try o.lowerType(.usize, .by_value), + try o.lowerType(.usize, .as_value), "", ); const target_ptr_ptr = try self.ptraddScaled( @@ -1510,7 +1508,7 @@ fn lowerSwitchDispatch( // The switch prongs will correspond to our scalar cases. Ranges will // be handled by conditional branches in the `else` prong. - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const cond_int = if (cond_ty.zigTypeTag(zcu) == .pointer) try self.wip.cast(.ptrtoint, cond, llvm_usize, "") else @@ -1725,7 +1723,7 @@ fn lowerTry( if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, ); }; - const zero = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const zero = try o.builder.intValue(try o.errorIntType(.as_value), 0); const is_err = try fg.wip.icmp(.ne, loaded, zero, ""); const return_block = try fg.wip.block(1, "TryRet"); @@ -1862,8 +1860,8 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod const table_includes_else = item_count != table_len; break :jmp_table .{ - .min = try o.lowerValue(min.toIntern(), .by_value), - .max = try o.lowerValue(max.toIntern(), .by_value), + .min = try o.lowerValue(min.toIntern(), .as_value), + .max = try o.lowerValue(max.toIntern(), .as_value), .in_bounds_hint = if (table_includes_else) .none else switch (switch_br.getElseHint()) { .none, .cold => .none, .unpredictable => .unpredictable, @@ -2021,142 +2019,102 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand_ty = self.typeOf(ty_op.operand); const array_ty = operand_ty.childType(zcu); - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(zcu)); - const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst), .by_value); + const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst), .as_value); const operand = try self.resolveInst(ty_op.operand); return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, ""); } -fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { - const o = self.object; +fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { + const o = fg.object; const zcu = o.zcu; - const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.typeOf(ty_op.operand); + const operand = try fg.resolveInst(ty_op.operand); + const operand_ty = fg.typeOf(ty_op.operand); const operand_scalar_ty = operand_ty.scalarType(zcu); - const is_signed_int = operand_scalar_ty.isSignedInt(zcu); + const operand_scalar_info = operand_scalar_ty.intInfo(zcu); - const dest_ty = self.typeOfIndex(inst); + const dest_ty = fg.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv( - if (is_signed_int) .signed else .unsigned, - operand, - dest_llvm_ty, - "", - ); + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target)) + return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), ""); - const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(zcu))) orelse { - return self.todo("float_from_int on {d} bit integer", .{operand_scalar_ty.bitSize(zcu)}); + const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse { + return fg.todo("float_from_int on {d} bit integer", .{operand_scalar_info.bits}); }; - const rt_int_ty = try o.builder.intType(rt_int_bits); - var extended = try self.wip.conv( - if (is_signed_int) .signed else .unsigned, + const vector_len = if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null; + const rt_llvm_int_ty = try o.lowerType(rt_int_ty, .as_value); + const extended = try fg.wip.conv( + .fromStdLang(operand_scalar_info.signedness), operand, - rt_int_ty, + if (vector_len) |len| + try o.builder.vectorType(.normal, len, rt_llvm_int_ty) + else + rt_llvm_int_ty, "", ); - const dest_bits = dest_scalar_ty.floatBits(target); - const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); - const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); - const sign_prefix = if (is_signed_int) "" else "un"; const fn_name = try o.builder.strtabStringFmt("__float{s}{s}i{s}f", .{ - sign_prefix, - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, + switch (operand_scalar_info.signedness) { + .signed => "", + .unsigned => "un", + }, + compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits), + compilerRtFloatAbbrev(target, dest_scalar_ty.floatBits(target)), }); - - var param_type = rt_int_ty; - if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard - // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have. - param_type = try o.builder.vectorType(.normal, 2, .i64); - extended = try self.wip.cast(.bitcast, extended, param_type, ""); - } - - const libc_fn = try o.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{extended}, - "", - ); + return fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{rt_int_ty.toIntern()}, + .return_type = dest_scalar_ty.toIntern(), + }, &.{extended}, vector_len); } fn airIntFromFloat( - self: *FuncGen, + fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind, ) TodoError!Builder.Value { _ = fast; - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); - const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.typeOf(ty_op.operand); + const operand = try fg.resolveInst(ty_op.operand); + const operand_ty = fg.typeOf(ty_op.operand); const operand_scalar_ty = operand_ty.scalarType(zcu); - const dest_ty = self.typeOfIndex(inst); + const dest_ty = fg.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); + const dest_llvm_ty = try o.lowerType(dest_ty, .as_value); + const dest_scalar_info = dest_scalar_ty.intInfo(zcu); - if (intrinsicsAllowed(operand_scalar_ty, target)) { + if (intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) { // TODO set fast math flag - return self.wip.conv( - if (dest_scalar_ty.isSignedInt(zcu)) .signed else .unsigned, - operand, - dest_llvm_ty, - "", - ); + return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, ""); } - const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(zcu))) orelse { - return self.todo("int_from_float to {d} bit integer", .{dest_scalar_ty.bitSize(zcu)}); + const rt_int_ty = compilerRtPromoteInt(dest_scalar_info) orelse { + return fg.todo("int_from_float to {d} bit integer", .{dest_scalar_info.bits}); }; - const ret_ty = try o.builder.intType(rt_int_bits); - const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard - // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have. - break :b try o.builder.vectorType(.normal, 2, .i64); - } else ret_ty; - - const operand_bits = operand_scalar_ty.floatBits(target); - const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); - - const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); - const sign_prefix = if (dest_scalar_ty.isSignedInt(zcu)) "" else "uns"; - const fn_name = try o.builder.strtabStringFmt("__fix{s}{s}f{s}i", .{ - sign_prefix, - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, + switch (dest_scalar_info.signedness) { + .signed => "", + .unsigned => "uns", + }, + compilerRtFloatAbbrev(target, operand_scalar_ty.floatBits(target)), + compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits), }); - - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty); - var result = try self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - - if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, ""); - if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, ""); - return result; + const result = try fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{operand_scalar_ty.toIntern()}, + .return_type = rt_int_ty.toIntern(), + }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null); + return fg.wip.cast(.trunc, result, try o.lowerType(dest_ty, .as_value), ""); } fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value { @@ -2167,7 +2125,7 @@ fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!B fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value { const o = fg.object; const zcu = o.zcu; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); switch (ty.ptrSize(zcu)) { .slice => { const len = try fg.wip.extractValue(ptr, &.{1}, ""); @@ -2365,7 +2323,7 @@ fn airAggFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder. }, .float => { // bitcast int->float - return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty, .by_value), ""); + return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty, .as_value), ""); }, } } @@ -2395,8 +2353,8 @@ fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu); if (field_offset == 0) return field_ptr; - const res_ty = try o.lowerType(ty_pl.ty.toType(), .by_value); - const llvm_usize = try o.lowerType(.usize, .by_value); + const res_ty = try o.lowerType(ty_pl.ty.toType(), .as_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, ""); const base_ptr_int = try self.wip.bin( @@ -2612,7 +2570,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { const output_inst = try self.resolveInst(output.operand); const output_ty = self.typeOf(output.operand); assert(output_ty.zigTypeTag(zcu) == .pointer); - const elem_llvm_ty = try o.lowerType(output_ty.childType(zcu), .by_value); + const elem_llvm_ty = try o.lowerType(output_ty.childType(zcu), .as_value); switch (constraint[0]) { '=' => {}, @@ -2650,7 +2608,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_ret_indirect[output.index] = false; const ret_ty = self.typeOfIndex(inst); - llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty, .by_value); + llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty, .as_value); llvm_ret_i += 1; } @@ -2689,7 +2647,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); } else { const alignment = arg_ty.abiAlignment(zcu).toLlvm(); - const arg_llvm_ty = try o.lowerType(arg_ty, .by_value); + const arg_llvm_ty = try o.lowerType(arg_ty, .as_value); const load_inst = try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); llvm_param_values[llvm_param_i] = load_inst; llvm_param_types[llvm_param_i] = arg_llvm_ty; @@ -2729,7 +2687,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') blk: { if (!is_by_ref) self.maybeMarkAllowZeroAccess(arg_ty.ptrInfo(zcu)); - break :blk try o.lowerType(if (is_by_ref) arg_ty else arg_ty.childType(zcu), .by_value); + break :blk try o.lowerType(if (is_by_ref) arg_ty else arg_ty.childType(zcu), .as_value); } else .none; llvm_param_i += 1; @@ -2743,7 +2701,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { if (constraint[0] != '+') continue; const rw_ty = self.typeOf(output.operand); - const llvm_elem_ty = try o.lowerType(rw_ty.childType(zcu), .by_value); + const llvm_elem_ty = try o.lowerType(rw_ty.childType(zcu), .as_value); if (llvm_ret_indirect[output.index]) { llvm_param_values[llvm_param_i] = llvm_rw_vals[output.index]; llvm_param_types[llvm_param_i] = llvm_rw_vals[output.index].typeOfWip(&self.wip); @@ -2957,7 +2915,7 @@ fn airIsNonNull( )); return self.wip.icmp(cond, slice_ptr, try o.builder.nullValue(ptr_ty), ""); } - return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(try o.lowerType(optional_ty, .by_value)), ""); + return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(try o.lowerType(optional_ty, .as_value)), ""); } comptime assert(optional_layout_version == 3); @@ -2986,7 +2944,7 @@ fn airIsErr( const operand_ty = self.typeOf(un_op); const err_union_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; const payload_ty = err_union_ty.errorUnionPayload(zcu); - const zero_err = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const zero_err = try o.builder.intValue(try o.errorIntType(.as_value), 0); const access_kind: Builder.MemoryAccessKind = if (operand_is_ptr and operand_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -3156,7 +3114,7 @@ fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro const err_union_ptr_align = err_union_ptr_ty.ptrAlignment(zcu); const payload_ty = err_union_ty.errorUnionPayload(zcu); - const non_error_val = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const non_error_val = try o.builder.intValue(try o.errorIntType(.as_value), 0); const access_kind: Builder.MemoryAccessKind = if (err_union_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -3234,7 +3192,7 @@ fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error! const payload_ty = self.typeOf(ty_op.operand); assert(payload_ty.hasRuntimeBits(zcu)); assert(isByRef(err_un_ty, zcu)); // error unions with runtime bits are always by-ref - const ok_err_code = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const ok_err_code = try o.builder.intValue(try o.errorIntType(.as_value), 0); const result_ptr = try self.buildZigAlloca(err_un_ty, .none); @@ -3273,7 +3231,7 @@ fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@backingInt(inst)].pl_op; const index = pl_op.payload; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.size", &.{llvm_usize}, &.{ try o.builder.intValue(.i32, index), }, ""); @@ -3283,7 +3241,7 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@backingInt(inst)].pl_op; const index = pl_op.payload; - const llvm_isize = try o.lowerType(.isize, .by_value); + const llvm_isize = try o.lowerType(.isize, .as_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.grow", &.{llvm_isize}, &.{ try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand), }, ""); @@ -3310,7 +3268,7 @@ fn airMin(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, if (scalar_ty.isSignedInt(zcu)) .smin else .umin, - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3330,7 +3288,7 @@ fn airMax(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, if (scalar_ty.isSignedInt(zcu)) .smax else .umax, - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3342,7 +3300,7 @@ fn airSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr = try self.resolveInst(bin_op.lhs); const len = try self.resolveInst(bin_op.rhs); const inst_ty = self.typeOfIndex(inst); - return self.wip.buildAggregate(try self.object.lowerType(inst_ty, .by_value), &.{ ptr, len }, ""); + return self.wip.buildAggregate(try self.object.lowerType(inst_ty, .as_value), &.{ ptr, len }, ""); } fn airAdd(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { @@ -3373,7 +3331,7 @@ fn airSafeArithmetic( const scalar_ty = inst_ty.scalarType(zcu); const intrinsic = if (scalar_ty.isSignedInt(zcu)) signed_intrinsic else unsigned_intrinsic; - const llvm_inst_ty = try o.lowerType(inst_ty, .by_value); + const llvm_inst_ty = try o.lowerType(inst_ty, .as_value); const results = try fg.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, ""); @@ -3423,7 +3381,7 @@ fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"sadd.sat" else .@"uadd.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3462,7 +3420,7 @@ fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"ssub.sat" else .@"usub.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3501,7 +3459,7 @@ fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"smul.fix.sat" else .@"umul.fix.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs, .@"0" }, "", ); @@ -3545,8 +3503,8 @@ fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) return self.buildFloatOp(.floor, fast, inst_ty, 1, .{result}); } if (scalar_ty.isSignedInt(zcu)) { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; var bfa_buf: ExpectedContents = undefined; @@ -3594,8 +3552,8 @@ fn airDivCeil(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) return self.buildFloatOp(.ceil, fast, inst_ty, 1, .{result}); } if (scalar_ty.isSignedInt(zcu)) { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; var bfa_buf: ExpectedContents = undefined; @@ -3634,8 +3592,8 @@ fn airDivCeil(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) const correction = try self.wip.cast(.zext, need_correction, inst_llvm_ty, "divCeil.correction"); return self.wip.bin(.@"add nsw", div, correction, "divCeil"); } else { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const zero = try o.builder.splatValue( inst_llvm_ty, @@ -3692,15 +3650,17 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo const lhs = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); const inst_ty = self.typeOfIndex(inst); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); const scalar_ty = inst_ty.scalarType(zcu); if (scalar_ty.isRuntimeFloat()) { const a = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ lhs, rhs }); const b = try self.buildFloatOp(.add, fast, inst_ty, 2, .{ a, rhs }); const c = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ b, rhs }); - const zero = try o.builder.zeroInitValue(inst_llvm_ty); - const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero }); + const zero = if (isByRef(inst_ty, zcu)) zero: { + const zero = try o.builder.zeroInitConst(try o.lowerType(inst_ty, .in_memory)); + break :zero try o.lowerConstRef(zero, inst_ty.abiAlignment(zcu).toLlvm()); + } else try o.builder.zeroInitConst(try o.lowerType(inst_ty, .as_value)); + const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero.toValue() }); return self.wip.select(fast, ltz, c, a, ""); } if (scalar_ty.isSignedInt(zcu)) { @@ -3709,6 +3669,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa); const allocator = bfa.allocator(); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const scalar_bits = scalar_ty.intInfo(zcu).bits; var smin_big_int: std.math.big.int.Mutable = .{ .limbs = try allocator.alloc( @@ -3721,7 +3682,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo defer allocator.free(smin_big_int.limbs); smin_big_int.setTwosCompIntLimit(.min, .signed, scalar_bits); const smin = try o.builder.splatValue(inst_llvm_ty, try o.builder.bigIntConst( - try o.lowerType(scalar_ty, .by_value), + try o.lowerType(scalar_ty, .as_value), smin_big_int.toConst(), )); @@ -3757,7 +3718,7 @@ fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const ptr_or_slice = try self.resolveInst(bin_op.lhs); - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const ptr_ty = self.typeOf(bin_op.lhs); const elem_ty = ptr_ty.indexableElem(zcu); const ptr = switch (ptr_ty.ptrSize(zcu)) { @@ -3790,7 +3751,7 @@ fn airOverflow( assert(isByRef(inst_ty, zcu)); // auto structs are by-ref const intrinsic = if (scalar_ty.isSignedInt(zcu)) signed_intrinsic else unsigned_intrinsic; - const llvm_lhs_ty = try o.lowerType(lhs_ty, .by_value); + const llvm_lhs_ty = try o.lowerType(lhs_ty, .as_value); const results = try self.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, ""); @@ -3818,34 +3779,97 @@ fn airOverflow( } fn buildElementwiseCall( - self: *FuncGen, - llvm_fn: Builder.Function.Index, - args_vectors: []const Builder.Value, - result_vector: Builder.Value, - vector_len: usize, + fg: *FuncGen, + fn_name: Builder.StrtabString, + fn_info: Object.FuncInfo, + arg_values: []const Builder.Value, + vector_len: ?u32, ) Allocator.Error!Builder.Value { - const o = self.object; - assert(args_vectors.len <= 3); + const o = fg.object; + const zcu = o.zcu; + const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info); - var i: usize = 0; - var result = result_vector; - while (i < vector_len) : (i += 1) { - const index_i32 = try o.builder.intValue(.i32, i); + const iterations = vector_len orelse 1; + const ret_ty: Type = .fromInterned(fn_info.return_type); + const ret_is_by_ref = isByRef(ret_ty, zcu); + if (iterations > 1 and (fn_info.return_type == .void_type or ret_is_by_ref) and + for (fn_info.param_types) |param_type| { + if (!isByRef(.fromInterned(param_type), zcu)) break false; + } else true) + { + const entry_block = fg.wip.cursor.block; + const loop_block = try fg.wip.block(2, "elementwise.loop"); + const done_block = try fg.wip.block(1, "elementwise.done"); - var args: [3]Builder.Value = undefined; - for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| { - arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, ""); + const result_ptr = if (fn_info.return_type == .void_type) .none else result_ptr: { + const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory); + break :result_ptr try fg.buildAlloca( + if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty, + ret_ty.abiAlignment(zcu).toLlvm(), + ); + }; + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const index = try fg.wip.phi(.i32, "elementwise.index"); + + var arg_elems_buf: [3]Builder.Value = undefined; + const arg_elems = arg_elems_buf[0..arg_values.len]; + for (arg_elems, fn_info.param_types, arg_values) |*arg_elem, param_type, arg_value| { + const arg_elem_ptr = try fg.ptraddScaled(arg_value, index.toValue(), Type.fromInterned(param_type).abiSize(zcu)); + arg_elem.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal); + } + const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems); + if (fn_info.return_type == .void_type) { + assert(result_elem == .none); + } else if (result_elem != .none) { + const result_elem_ptr = try fg.ptraddScaled(result_ptr, index.toValue(), ret_ty.abiSize(zcu)); + try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal); } - const result_elem = try self.wip.call( - .normal, - .ccc, - .none, - llvm_fn.typeOf(&o.builder), - llvm_fn.toValue(&o.builder), - args[0..args_vectors.len], - "", + + const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "elementwise.next_index"); + index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "elementwise.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + return result_ptr; + } + + var result = if (fn_info.return_type == .void_type) .none else if (ret_is_by_ref) result: { + const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory); + break :result try fg.buildAlloca( + if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty, + ret_ty.abiAlignment(zcu).toLlvm(), ); - result = try self.wip.insertElement(result, result_elem, index_i32, ""); + } else if (vector_len) |len| try o.builder.poisonValue( + try o.builder.vectorType(.normal, len, try o.lowerType(ret_ty, .as_value)), + ) else .none; + for (0..iterations) |index| { + const index_value = try o.builder.intValue(.i32, index); + var arg_elems_buf: [3]Builder.Value = undefined; + const arg_elems = arg_elems_buf[0..arg_values.len]; + for (arg_elems, fn_info.param_types, arg_values) |*arg_elem_value, param_type, arg_value| { + const arg_ty: Type = .fromInterned(param_type); + if (isByRef(arg_ty, zcu)) { + const arg_elem_ptr = try fg.ptraddConst(arg_value, index * arg_ty.abiSize(zcu)); + arg_elem_value.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal); + } else if (vector_len) |_| { + arg_elem_value.* = try fg.wip.extractElement(arg_value, index_value, "elementwise.arg_elem"); + } else arg_elem_value.* = arg_value; + } + const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems); + if (fn_info.return_type == .void_type) { + assert(result_elem == .none); + } else if (ret_is_by_ref) { + const result_elem_ptr = try fg.ptraddConst(result, index * ret_ty.abiSize(zcu)); + try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal); + } else if (vector_len) |_| { + result = try fg.wip.insertElement(result, result_elem, index_value, "elementwise.result"); + } else { + assert(result == .none); + result = result_elem; + } } return result; } @@ -3853,19 +3877,18 @@ fn buildElementwiseCall( /// Creates a floating point comparison by lowering to the appropriate /// hardware instruction or softfloat routine for the target fn buildFloatCmp( - self: *FuncGen, + fg: *FuncGen, fast: Builder.FastMathKind, pred: math.CompareOperator, ty: Type, params: [2]Builder.Value, ) Allocator.Error!Builder.Value { - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - if (intrinsicsAllowed(scalar_ty, target)) { + if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) { const cond: Builder.FloatCondition = switch (pred) { .eq => .oeq, .neq => .une, @@ -3874,53 +3897,33 @@ fn buildFloatCmp( .gt => .ogt, .gte => .oge, }; - return self.wip.fcmp(fast, cond, params[0], params[1], ""); + return fg.wip.fcmp(fast, cond, params[0], params[1], ""); } - const float_bits = scalar_ty.floatBits(target); - const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits); - const fn_base_name = switch (pred) { - .neq => "ne", - .eq => "eq", - .lt => "lt", - .lte => "le", - .gt => "gt", - .gte => "ge", - }; - const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{ fn_base_name, compiler_rt_float_abbrev }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{ scalar_llvm_ty, scalar_llvm_ty }, .i32); - - const int_cond: Builder.IntegerCondition = switch (pred) { + const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{ + switch (pred) { + .neq => "ne", + .eq => "eq", + .lt => "lt", + .lte => "le", + .gt => "gt", + .gte => "ge", + }, + compilerRtFloatAbbrev(target, scalar_ty.floatBits(target)), + }); + const result = try fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() }, + .return_type = .i32_type, + }, ¶ms, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null); + return fg.wip.icmp(switch (pred) { .eq => .eq, .neq => .ne, .lt => .slt, .lte => .sle, .gt => .sgt, .gte => .sge, - }; - - if (ty.zigTypeTag(zcu) == .vector) { - const vec_len = ty.vectorLen(zcu); - const vector_result_ty = try o.builder.vectorType(.normal, vec_len, .i32); - - const init = try o.builder.poisonValue(vector_result_ty); - const result = try self.buildElementwiseCall(libc_fn, ¶ms, init, vec_len); - - const zero_vector = try o.builder.splatValue(vector_result_ty, .@"0"); - return self.wip.icmp(int_cond, result, zero_vector, ""); - } - - const result = try self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - ¶ms, - "", - ); - return self.wip.icmp(int_cond, result, .@"0", ""); + }, result, try o.builder.splatValue(result.typeOfWip(&fg.wip), .@"0"), ""); } const FloatOp = enum { @@ -3949,32 +3952,30 @@ const FloatOp = enum { trunc, }; -const FloatOpStrat = union(enum) { - intrinsic: []const u8, - libc: Builder.String, -}; - /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.) /// by lowering to the appropriate hardware instruction or softfloat /// routine for the target fn buildFloatOp( - self: *FuncGen, + fg: *FuncGen, comptime op: FloatOp, fast: Builder.FastMathKind, ty: Type, comptime params_len: usize, params: [params_len]Builder.Value, ) Allocator.Error!Builder.Value { - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const llvm_ty = try o.lowerType(ty, .by_value); - if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { + switch (op) { // Some operations are dedicated LLVM instructions, not available as intrinsics - .neg => return self.wip.un(.fneg, params[0], ""), - .add, .sub, .mul, .div, .fmod => return self.wip.bin(switch (fast) { + .neg => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) return fg.wip.un(.fneg, params[0], ""), + .add, .sub, .mul, .div, .fmod => if (intrinsicsAllowed(switch (op) { + else => unreachable, + .add, .sub, .mul, .div => .compiler_rt, + .fmod => .libc, + }, scalar_ty, target)) return fg.wip.bin(switch (fast) { .normal => switch (op) { .add => .fadd, .sub => .fsub, @@ -3992,6 +3993,7 @@ fn buildFloatOp( else => unreachable, }, }, params[0], params[1], ""), + .fma, .fmax, .fmin, .ceil, @@ -4006,9 +4008,10 @@ fn buildFloatOp( .round, .sin, .sqrt, + .tan, .trunc, - .fma, - => return self.wip.callIntrinsic(fast, .none, switch (op) { + => if (intrinsicsAllowed(.libc, scalar_ty, target)) return fg.wip.callIntrinsic(fast, .none, switch (op) { + .fma => .fma, .fmax => .maxnum, .fmin => .minnum, .ceil => .ceil, @@ -4023,39 +4026,154 @@ fn buildFloatOp( .round => .round, .sin => .sin, .sqrt => .sqrt, + .tan => .tan, .trunc => .trunc, - .fma => .fma, else => unreachable, - }, &.{llvm_ty}, ¶ms, ""), - .tan => unreachable, - }; + }, &.{try o.lowerType(ty, .as_value)}, ¶ms, ""), + } const float_bits = scalar_ty.floatBits(target); const fn_name = switch (op) { - .neg => { - // In this case we can generate a softfloat negation by XORing the - // bits with a constant. + // In these cases we can generate a softfloat operation by modifying the sign bit using a bitwise operation. + .neg, .fabs => if (isByRef(scalar_ty, zcu)) { + const is_vector = ty.toIntern() != scalar_ty.toIntern(); + const result_ptr = try fg.buildZigAlloca(ty, .none); + const entry_block = fg.wip.cursor.block; + const loop_block, const done_block, const llvm_usize_ty, const offset, const elem, const result_elem = if (is_vector) loop: { + const loop_block = try fg.wip.block(2, "neg_fabs.loop"); + const done_block = try fg.wip.block(1, "neg_fabs.done"); + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const llvm_usize_ty = try o.lowerType(.usize, .as_value); + const offset = try fg.wip.phi(llvm_usize_ty, "neg_fabs.offset"); + break :loop .{ + loop_block, + done_block, + llvm_usize_ty, + offset, + try fg.ptraddScaled(params[0], offset.toValue(), 1), + try fg.ptraddScaled(result_ptr, offset.toValue(), 1), + }; + } else .{ undefined, undefined, undefined, undefined, params[0], result_ptr }; + switch (scalar_ty.floatBits(target)) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.load( + try fg.ptraddConst(elem, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + .u64, + .normal, + ); + const exponent = try fg.load( + try fg.ptraddConst(elem, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + .u16, + .normal, + ); + const exponent_sign_bit: u16 = 1 << (16 - 1); + const updated_exponent = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, exponent, try o.builder.intValue(.i16, switch (op) { + else => unreachable, + .neg => exponent_sign_bit, + .fabs => exponent_sign_bit - 1, + }), "neg_fabs.updated_exponent"); + try fg.store( + try fg.ptraddConst(result_elem, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_elem, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + updated_exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.load( + try fg.ptraddConst(elem, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + .u64, + .normal, + ); + const hi = try fg.load( + try fg.ptraddConst(elem, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + .u64, + .normal, + ); + const hi_sign_bit: u64 = 1 << (64 - 1); + const updated_hi = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, hi, try o.builder.intValue(.i64, switch (op) { + else => unreachable, + .neg => hi_sign_bit, + .fabs => hi_sign_bit - 1, + }), "neg_fabs.updated_hi"); + try fg.store( + try fg.ptraddConst(result_elem, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_elem, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + updated_hi, + .u64, + .normal, + ); + }, + } + if (is_vector) { + const next_offset = try fg.wip.bin(.@"add nuw", offset.toValue(), try o.builder.intValue(llvm_usize_ty, scalar_ty.abiSize(zcu)), "neg_fabs.next_offset"); + offset.finish(&.{ try o.builder.intValue(llvm_usize_ty, 0), next_offset }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_offset, try o.builder.intValue(llvm_usize_ty, ty.abiSize(zcu)), "neg_fabs.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + } + return result_ptr; + } else { const int_ty = try o.builder.intType(@intCast(float_bits)); const cast_ty = switch (ty.zigTypeTag(zcu)) { .vector => try o.builder.vectorType(.normal, ty.vectorLen(zcu), int_ty), else => int_ty, }; - const sign_mask = try o.builder.splatValue( - cast_ty, - try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)), - ); - const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, ""); - const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, ""); - return self.wip.cast(.bitcast, result, llvm_ty, ""); + const sign_bit = @as(u128, 1) << @intCast(float_bits - 1); + const bitwise_rhs = try o.builder.splatValue(cast_ty, try o.builder.intConst(int_ty, switch (op) { + else => unreachable, + .neg => sign_bit, + .fabs => sign_bit - 1, + })); + const bitcasted_operand = try fg.wip.cast(.bitcast, params[0], cast_ty, ""); + const result = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, bitcasted_operand, bitwise_rhs, ""); + const llvm_ty = try o.lowerType(ty, .as_value); + return fg.wip.cast(.bitcast, result, llvm_ty, ""); }, .add, .sub, .div, .mul => try o.builder.strtabStringFmt("__{s}{s}f3", .{ - @tagName(op), compilerRtFloatAbbrev(float_bits), + @tagName(op), compilerRtFloatAbbrev(target, float_bits), }), .ceil, .cos, .exp, .exp2, - .fabs, .floor, .fma, .fmax, @@ -4073,27 +4191,27 @@ fn buildFloatOp( libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits), }), }; + return fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &@as([params_len]InternPool.Index, @splat(scalar_ty.toIntern())), + .return_type = scalar_ty.toIntern(), + }, ¶ms, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null); +} - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const libc_fn = try o.getLibcFunction( - fn_name, - @as([3]Builder.Type, @splat(scalar_llvm_ty))[0..params.len], - scalar_llvm_ty, - ); - if (ty.zigTypeTag(zcu) == .vector) { - const result = try o.builder.poisonValue(llvm_ty); - return self.buildElementwiseCall(libc_fn, ¶ms, result, ty.vectorLen(zcu)); - } - - return self.wip.call( - fast.toCallKind(), - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - ¶ms, - "", - ); +/// Creates a floating point cast operation by lowering to the specified softfloat routine. +fn buildFloatCastCall( + fg: *FuncGen, + dest_ty: Type, + fn_name: Builder.StrtabString, + operand_ty: Type, + operand: Builder.Value, +) Allocator.Error!Builder.Value { + const zcu = fg.object.zcu; + return fg.buildElementwiseCall(fn_name, .{ + .cc = zcu.getTarget().cCallingConvention().?, + .param_types = &.{operand_ty.scalarType(zcu).toIntern()}, + .return_type = dest_ty.scalarType(zcu).toIntern(), + }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null); } fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4129,7 +4247,7 @@ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Buil const dest_ty = self.typeOfIndex(inst); assert(isByRef(dest_ty, zcu)); // auto structs are by-ref - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); const result = try self.wip.bin(.shl, lhs, casted_rhs, ""); const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) @@ -4196,7 +4314,7 @@ fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val } const lhs_scalar_ty = lhs_ty.scalarType(zcu); - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); return self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) .@"shl nsw" else @@ -4217,7 +4335,7 @@ fn airShl(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { // features which we do not use. Therefore this branch is currently impossible. unreachable; } - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); return self.wip.bin(.shl, lhs, casted_rhs, ""); } @@ -4231,8 +4349,8 @@ fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const lhs_ty = self.typeOf(bin_op.lhs); const lhs_info = lhs_ty.intInfo(zcu); - const llvm_lhs_ty = try o.lowerType(lhs_ty, .by_value); - const llvm_lhs_scalar_ty = try o.lowerType(lhs_ty.scalarType(zcu), .by_value); + const llvm_lhs_ty = try o.lowerType(lhs_ty, .as_value); + const llvm_lhs_scalar_ty = try o.lowerType(lhs_ty.scalarType(zcu), .as_value); const rhs_ty = self.typeOf(bin_op.rhs); if (lhs_ty.isVector(zcu) and !rhs_ty.isVector(zcu)) { @@ -4242,8 +4360,8 @@ fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value } const rhs_info = rhs_ty.intInfo(zcu); assert(rhs_info.signedness == .unsigned); - const llvm_rhs_ty = try o.lowerType(rhs_ty, .by_value); - const llvm_rhs_scalar_ty = try o.lowerType(rhs_ty.scalarType(zcu), .by_value); + const llvm_rhs_ty = try o.lowerType(rhs_ty, .as_value); + const llvm_rhs_scalar_ty = try o.lowerType(rhs_ty.scalarType(zcu), .as_value); const result = try self.wip.callIntrinsic( .normal, @@ -4319,7 +4437,7 @@ fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) Allocator.Error! } const lhs_scalar_ty = lhs_ty.scalarType(zcu); - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); const is_signed_int = lhs_scalar_ty.isSignedInt(zcu); return self.wip.bin(if (is_exact) @@ -4340,7 +4458,7 @@ fn airAbs(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, .abs, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{ operand, .false }, "", ), @@ -4354,7 +4472,7 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! const zcu = o.zcu; const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const dest_ty = fg.typeOfIndex(inst); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); + const dest_llvm_ty = try o.lowerType(dest_ty, .as_value); const operand = try fg.resolveInst(ty_op.operand); const operand_ty = fg.typeOf(ty_op.operand); const operand_info = operand_ty.intInfo(zcu); @@ -4382,8 +4500,8 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! if (!have_min_check and !have_max_check) break :bounds_check; - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const operand_scalar_llvm_ty = try o.lowerType(operand_scalar, .by_value); + const operand_llvm_ty = try o.lowerType(operand_ty, .as_value); + const operand_scalar_llvm_ty = try o.lowerType(operand_scalar, .as_value); const is_vector = operand_ty.zigTypeTag(zcu) == .vector; assert(is_vector == (dest_ty.zigTypeTag(zcu) == .vector)); @@ -4461,7 +4579,7 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); - const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst), .by_value); + const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst), .as_value); return self.wip.cast(.trunc, operand, dest_llvm_ty, ""); } @@ -4471,32 +4589,20 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_ty = self.typeOfIndex(inst); + const dest_scalar_ty = dest_ty.scalarType(zcu); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { - return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .by_value), ""); - } else { - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); - - const dest_bits = dest_ty.floatBits(target); - const src_bits = operand_ty.floatBits(target); - const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{ - compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), - }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - } + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and + intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) + return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), ""); + const dest_bits = dest_scalar_ty.floatBits(target); + const src_bits = operand_scalar_ty.floatBits(target); + const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{ + compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits), + }); + return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand); } fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4505,38 +4611,20 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_ty = self.typeOfIndex(inst); + const dest_scalar_ty = dest_ty.scalarType(zcu); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { - return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .by_value), ""); - } else { - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); - - const dest_bits = dest_ty.scalarType(zcu).floatBits(target); - const src_bits = operand_ty.scalarType(zcu).floatBits(target); - const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{ - compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), - }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty); - if (dest_ty.isVector(zcu)) return self.buildElementwiseCall( - libc_fn, - &.{operand}, - try o.builder.poisonValue(dest_llvm_ty), - dest_ty.vectorLen(zcu), - ); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - } + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and + intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) + return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), ""); + const dest_bits = dest_scalar_ty.floatBits(target); + const src_bits = operand_scalar_ty.floatBits(target); + const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{ + compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits), + }); + return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand); } fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value { @@ -4558,12 +4646,145 @@ fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! // * bool/int/float <-> bool/int/float // * `@Vector(n, A)` <-> `@Vector(n, B)` // - // All of these cases can be handled by LLVM's `bitcast` instruction. + // Most of these cases can be handled by LLVM's `bitcast` instruction, except when + // a non-native type like `f80` is used. - assert(!isByRef(operand_ty, zcu)); - assert(!isByRef(dest_ty, zcu)); + if (isByRef(operand_ty, zcu)) { + const operand_scalar_ty = operand_ty.scalarType(zcu); + const target = zcu.getTarget(); + const bits = operand_scalar_ty.floatBits(target); + const dest_scalar_ty = dest_ty.scalarType(zcu); + if (isByRef(dest_ty, zcu)) { + assert(dest_scalar_ty.floatBits(target) == bits); + return operand; + } + assert(dest_scalar_ty.intInfo(zcu).bits == bits); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern()) + operand_ty.vectorLen(zcu) + else + null; + const operand_scalar_size = operand_scalar_ty.abiSize(zcu); + var result = if (len) |_| + try o.builder.poisonValue(try o.lowerType(dest_ty, .as_value)) + else + undefined; + for (0..len orelse 1) |index| { + const result_elem = result_elem: switch (bits) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + .u64, + .normal, + ); + const exponent = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + .u16, + .normal, + ); + const casted_mantissa = try fg.wip.cast(.zext, mantissa, .i80, "bitCast.casted_mantissa"); + const casted_exponent = try fg.wip.cast(.zext, exponent, .i80, "bitCast.casted_exponent"); + const shifted_exponent = try fg.wip.bin(.@"shl nuw", casted_exponent, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent"); + break :result_elem try fg.wip.bin(.@"or", casted_mantissa, shifted_exponent, "bitCast.result_elem"); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + .u64, + .normal, + ); + const hi = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + .u64, + .normal, + ); + const casted_lo = try fg.wip.cast(.zext, lo, .i128, "bitCast.casted_lo"); + const casted_hi = try fg.wip.cast(.zext, hi, .i128, "bitCast.casted_hi"); + const shifted_hi = try fg.wip.bin(.@"shl nuw", casted_hi, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi"); + break :result_elem try fg.wip.bin(.@"or", casted_lo, shifted_hi, "bitCast.result_elem"); + }, + }; + result = if (len) |_| + try fg.wip.insertElement(result, result_elem, try o.builder.intValue(.i32, index), "elementwise.result") + else + result_elem; + } + return result; + } + + if (isByRef(dest_ty, zcu)) { + const dest_scalar_ty = dest_ty.scalarType(zcu); + const bits = dest_scalar_ty.floatBits(zcu.getTarget()); + assert(dest_scalar_ty.isRuntimeFloat()); + const operand_scalar_ty = operand_ty.scalarType(zcu); + assert(operand_scalar_ty.intInfo(zcu).bits == bits); + + const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern()) + operand_ty.vectorLen(zcu) + else + null; + const operand_scalar_size = operand_scalar_ty.abiSize(zcu); + const result_ptr = try fg.buildZigAlloca(dest_ty, .none); + for (0..len orelse 1) |index| { + const operand_elem = if (len) |_| + try fg.wip.extractElement(operand, try o.builder.intValue(.i32, index), "elementwise.operand_elem") + else + operand; + switch (bits) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.mantissa"); + const shifted_exponent = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent"); + const exponent = try fg.wip.cast(.@"trunc nuw", shifted_exponent, .i16, "bitCast.exponent"); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.lo"); + const shifted_hi = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi"); + const hi = try fg.wip.cast(.@"trunc nuw", shifted_hi, .i64, "bitCast.hi"); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + hi, + .u64, + .normal, + ); + }, + } + } + return result_ptr; + } + + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); const result = try fg.wip.cast(.bitcast, operand, llvm_dest_ty, ""); if (safety and dest_ty.zigTypeTag(zcu) == .@"enum" and !dest_ty.isNonexhaustiveEnum(zcu)) { const llvm_fn = try o.getIsNamedEnumValueFunction(dest_ty); @@ -4606,7 +4827,7 @@ fn airPtrFromInt(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val assert(dest_ty.scalarType(zcu).isPtrAtRuntime(zcu)); const operand = try fg.resolveInst(ty_op.operand); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); return fg.wip.cast(.inttoptr, operand, llvm_dest_ty, ""); } @@ -4620,7 +4841,7 @@ fn airIntFromPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val assert(dest_ty.scalarType(zcu).toIntern() == .usize_type); const operand = try fg.resolveInst(ty_op.operand); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); return fg.wip.cast(.ptrtoint, operand, llvm_dest_ty, ""); } @@ -4730,7 +4951,7 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr_align = ptr_ty.ptrAlignment(zcu); const elem_ty = ptr_ty.childType(zcu); if (!elem_ty.hasRuntimeBits(zcu)) { - return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); + return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue(); } return self.buildZigAlloca(elem_ty, ptr_align); } @@ -4743,7 +4964,7 @@ fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr_align = ptr_ty.ptrAlignment(zcu); const elem_ty = ptr_ty.childType(zcu); if (!elem_ty.hasRuntimeBits(zcu)) { - return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); + return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue(); } return self.buildZigAlloca(elem_ty, ptr_align); } @@ -4754,10 +4975,7 @@ fn buildZigAlloca(fg: *FuncGen, ty: Type, @"align": InternPool.Alignment) Alloca .none => ty.abiAlignment(o.zcu), else => |a| a, }; - return fg.buildAlloca( - try o.lowerType(ty, .in_memory), - resolved_align.toLlvm(), - ); + return fg.buildAlloca(try o.lowerType(ty, .in_memory), resolved_align.toLlvm()); } /// Unlike `WipFunction.alloca`, this puts the alloca instruction at the top of the function. @@ -4832,7 +5050,7 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu return .none; } - const len = try o.builder.intValue(try o.lowerType(.usize, .by_value), elem_ty.abiSize(zcu)); + const len = try o.builder.intValue(try o.lowerType(.usize, .as_value), elem_ty.abiSize(zcu)); _ = try fg.wip.callMemSet( ptr, ptr_alignment.toLlvm(), @@ -4850,24 +5068,31 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu const elem = try fg.resolveInst(bin_op.rhs); if (ptr_info.flags.vector_index != .none) { - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. - const vec_ty = try fg.pt.vectorType(.{ - .len = ptr_info.packed_offset.host_size, - .child = elem_ty.toIntern(), - }); + if (isByRef(elem_ty, zcu)) { + const offset = @backingInt(ptr_info.flags.vector_index) * elem_ty.abiSize(zcu); + const elem_ptr = try fg.ptraddConst(ptr, offset); + try fg.store(elem_ptr, ptr_alignment.offset(offset), elem, elem_ty, access_kind); + } else { + // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. + const vec_ty = try fg.pt.vectorType(.{ + .len = ptr_info.packed_offset.host_size, + .child = elem_ty.toIntern(), + }); - const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind); - const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); - const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, ""); + const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind); + const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); + const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, ""); + + try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind); + } - try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind); return .none; } if (ptr_info.packed_offset.host_size != 0) { // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8)); - const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .by_value); + const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value); const backing_int_val = try fg.load(ptr, ptr_alignment, backing_int_ty, access_kind); @@ -4927,32 +5152,98 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { if (ptr_info.flags.is_volatile) .@"volatile" else .normal; if (ptr_info.flags.vector_index != .none) { - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. - const vec_ty = try fg.pt.vectorType(.{ - .len = ptr_info.packed_offset.host_size, - .child = elem_ty.toIntern(), - }); - const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind); - const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); - return fg.wip.extractElement(vector_val, index_val, ""); + if (isByRef(elem_ty, zcu)) { + const elem_size = elem_ty.abiSize(zcu); + const offset = @backingInt(ptr_info.flags.vector_index) * elem_size; + const elem_ptr = try fg.ptraddConst(ptr, offset); + return fg.load(elem_ptr, ptr_align.offset(offset), elem_ty, access_kind); + } else { + // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. + const vec_ty = try fg.pt.vectorType(.{ + .len = ptr_info.packed_offset.host_size, + .child = elem_ty.toIntern(), + }); + const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind); + const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); + return fg.wip.extractElement(vector_val, index_val, ""); + } } if (ptr_info.packed_offset.host_size == 0) { return fg.load(ptr, ptr_align, elem_ty, access_kind); } - assert(!isByRef(elem_ty, zcu)); // all packable types are by-val - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8)); - const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .by_value); + const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value); const backing_int_val = try fg.load(ptr, ptr_align, backing_int_ty, .normal); const elem_bits = ptr_ty.childType(zcu).bitSize(zcu); const shift_amt = try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset); const shifted_value = try fg.wip.bin(.lshr, backing_int_val, shift_amt, ""); - const elem_llvm_ty = try o.lowerType(elem_ty, .by_value); + + if (isByRef(elem_ty, zcu)) { + const result_ptr = try fg.buildZigAlloca(elem_ty, .none); + switch (elem_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.wip.cast(.trunc, shifted_value, .i64, "load.mantissa"); + const shifted_exponent = try fg.wip.bin( + .lshr, + backing_int_val, + try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64), + "load.shifted_exponent", + ); + const exponent = try fg.wip.cast(.trunc, shifted_exponent, .i16, "load.exponent"); + + try fg.store( + try fg.ptraddConst(result_ptr, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.wip.cast(.trunc, shifted_value, .i64, "load.lo"); + const shifted_hi = try fg.wip.bin( + .lshr, + backing_int_val, + try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64), + "load.shifted_hi", + ); + const hi = try fg.wip.cast(.trunc, shifted_hi, .i64, "load.hi"); + + try fg.store( + try fg.ptraddConst(result_ptr, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + hi, + .u64, + .normal, + ); + }, + } + return result_ptr; + } + + const elem_llvm_ty = try o.lowerType(elem_ty, .as_value); if (elem_ty.zigTypeTag(zcu) == .float or elem_ty.zigTypeTag(zcu) == .vector) { const same_size_int = try o.builder.intType(@intCast(elem_bits)); @@ -5002,7 +5293,7 @@ fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { _ = inst; const o = self.object; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); if (!target_util.supportsReturnAddress(self.object.zcu.getTarget(), self.ownerModule().optimize_mode)) { // https://github.com/ziglang/zig/issues/11946 return o.builder.intValue(llvm_usize, 0); @@ -5014,7 +5305,7 @@ fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { _ = inst; const result = try self.wip.callIntrinsic(.normal, .none, .frameaddress, &.{.ptr}, &.{.@"0"}, ""); - return self.wip.cast(.ptrtoint, result, try self.object.lowerType(.usize, .by_value), ""); + return self.wip.cast(.ptrtoint, result, try self.object.lowerType(.usize, .as_value), ""); } fn airCmpxchg( @@ -5031,7 +5322,7 @@ fn airCmpxchg( var expected_value = try self.resolveInst(extra.expected_value); var new_value = try self.resolveInst(extra.new_value); const operand_ty = ptr_ty.childType(zcu); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); const llvm_abi_ty = try self.getAtomicAbiType(operand_ty, false); if (llvm_abi_ty != .none) { // operand needs widening and truncating @@ -5101,7 +5392,7 @@ fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float); const ordering = toLlvmAtomicOrdering(extra.ordering()); const llvm_abi_ty = try self.getAtomicAbiType(operand_ty, op == .xchg); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); const access_kind: Builder.MemoryAccessKind = if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -5130,7 +5421,7 @@ fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va // If we are storing a pointer we need to convert to and from a plain old integer. const non_ptr_operand = switch (operand_ty.zigTypeTag(zcu)) { - .pointer => try self.wip.cast(.ptrtoint, operand, try o.lowerType(.usize, .by_value), ""), + .pointer => try self.wip.cast(.ptrtoint, operand, try o.lowerType(.usize, .as_value), ""), else => operand, }; @@ -5169,7 +5460,7 @@ fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V Type.fromInterned(info.child).abiAlignment(zcu)).toLlvm(); const access_kind: Builder.MemoryAccessKind = if (info.flags.is_volatile) .@"volatile" else .normal; - const elem_llvm_ty = try o.lowerType(elem_ty, .by_value); + const elem_llvm_ty = try o.lowerType(elem_ty, .as_value); self.maybeMarkAllowZeroAccess(info); @@ -5503,11 +5794,11 @@ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{ operand, .false }, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) Allocator.Error!Builder.Value { @@ -5521,11 +5812,11 @@ fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5538,7 +5829,7 @@ fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const inst_ty = self.typeOfIndex(inst); var operand = try self.resolveInst(ty_op.operand); - var llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + var llvm_operand_ty = try o.lowerType(operand_ty, .as_value); if (bits % 16 == 8) { // If not an even byte-multiple, we need zero-extend + shift-left 1 byte @@ -5559,7 +5850,7 @@ fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const result = try self.wip.callIntrinsic(.normal, .none, .bswap, &.{llvm_operand_ty}, &.{operand}, ""); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5579,7 +5870,7 @@ fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Bui for (0..names.len) |name_index| { const err_int = ip.getErrorValueIfExists(names.get(ip)[name_index]).?; - const this_tag_int_value = try o.builder.intConst(try o.errorIntType(.by_value), err_int); + const this_tag_int_value = try o.builder.intConst(try o.errorIntType(.as_value), err_int); try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip); } self.wip.cursor = .{ .block = valid_block }; @@ -5638,7 +5929,7 @@ fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const slice_ty = self.typeOfIndex(inst); // If operand is small (e.g. `u8`), then signedness becomes a problem -- GEP always treats the index as signed. - const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(.usize, .by_value), ""); + const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(.usize, .as_value), ""); const error_name_table_ptr = try o.getErrorNameTable(); const error_name_ptr = try self.ptraddScaled(error_name_table_ptr.toValue(&o.builder), operand_usize, slice_ty.abiSize(zcu)); @@ -5649,7 +5940,7 @@ fn airSplat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const scalar = try self.resolveInst(ty_op.operand); const vector_ty = self.typeOfIndex(inst); - return self.wip.splatVector(try self.object.lowerType(vector_ty, .by_value), scalar, ""); + return self.wip.splatVector(try self.object.lowerType(vector_ty, .as_value), scalar, ""); } fn airSelect(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5672,9 +5963,9 @@ fn airShuffleOne(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const operand = try fg.resolveInst(unwrapped.operand); const mask = unwrapped.mask; const operand_ty = fg.typeOf(unwrapped.operand); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); - const llvm_result_ty = try o.lowerType(unwrapped.result_ty, .by_value); - const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); + const llvm_result_ty = try o.lowerType(unwrapped.result_ty, .as_value); + const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .as_value); const llvm_poison_elem = try o.builder.poisonConst(llvm_elem_ty); const llvm_poison_mask_elem = try o.builder.poisonConst(.i32); const llvm_mask_ty = try o.builder.vectorType(.normal, @intCast(mask.len), .i32); @@ -5704,7 +5995,7 @@ fn airShuffleOne(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val .elem => llvm_poison_elem, .value => |val| if (!Value.fromInterned(val).isUndef(zcu)) elem: { any_defined_comptime_value = true; - break :elem try o.lowerValue(val, .by_value); + break :elem try o.lowerValue(val, .as_value); } else llvm_poison_elem, }; } @@ -5776,7 +6067,7 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const unwrapped = fg.air.unwrapShuffleTwo(zcu, inst); const mask = unwrapped.mask; - const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .by_value); + const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .as_value); const llvm_mask_ty = try o.builder.vectorType(.normal, @intCast(mask.len), .i32); const llvm_poison_mask_elem = try o.builder.poisonConst(.i32); @@ -5848,95 +6139,25 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val ); } -/// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result. -/// -/// Equivalent to: -/// ``` -/// var accum: T = init; -/// for (0..i) |i| { -/// accum = llvm_fn(accum, vec[i]); -/// } -/// // result is 'accum' -/// ``` -fn buildReducedCall( - self: *FuncGen, - llvm_fn: Builder.Function.Index, - operand_vector: Builder.Value, - vector_len: usize, - accum_init: Builder.Value, -) Allocator.Error!Builder.Value { - const o = self.object; - const llvm_usize_ty = try o.lowerType(.usize, .by_value); - const llvm_vector_len = try o.builder.intValue(llvm_usize_ty, vector_len); - const llvm_result_ty = accum_init.typeOfWip(&self.wip); - - const entry_block = self.wip.cursor.block; - - const cond_block = try self.wip.block(2, "ReduceLoopCond"); - const body_block = try self.wip.block(1, "ReduceLoopBody"); - const exit_block = try self.wip.block(1, "ReduceLoopExit"); - - _ = try self.wip.br(cond_block); - - // ReduceLoopCond: - // %index = phi iN [0, %Entry], [%new_index, %ReduceLoopBody] - // %accum = phi T [%accum_init, %Entry], [%new_accum, %ReduceLoopBody] - // %cond = icmp ult iN %index, %vector_len - // br i1 %cond, label %ReduceLoopBody, label %ReduceLoopExit - self.wip.cursor = .{ .block = cond_block }; - const index = try self.wip.phi(llvm_usize_ty, ""); - const accum = try self.wip.phi(llvm_result_ty, ""); - const cond = try self.wip.icmp(.ult, index.toValue(), llvm_vector_len, ""); - _ = try self.wip.brCond(cond, body_block, exit_block, .none); - - // ReduceLoopBody: - // %elem = extractelement %operand_vec, iN %index - // %new_accum = call T @llvm_fn(T %accum, T %elem) - // %new_index = add nuw iN %index, 1 - // br label %ReduceLoopCond - self.wip.cursor = .{ .block = body_block }; - const elem = try self.wip.extractElement(operand_vector, index.toValue(), ""); - const new_accum = try self.wip.call( - .normal, - .ccc, - .none, - llvm_fn.typeOf(&o.builder), - llvm_fn.toValue(&o.builder), - &.{ accum.toValue(), elem }, - "", - ); - const new_index = try self.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(llvm_usize_ty, 1), ""); - _ = try self.wip.br(cond_block); - - const index_init = try o.builder.intValue(llvm_usize_ty, 0); - index.finish(&.{ index_init, new_index }, &.{ entry_block, body_block }, &self.wip); - accum.finish(&.{ accum_init, new_accum }, &.{ entry_block, body_block }, &self.wip); - - self.wip.cursor = .{ .block = exit_block }; - return accum.toValue(); -} - -fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { - const o = self.object; +fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); - const reduce = self.air.instructions.items(.data)[@backingInt(inst)].reduce; - const operand = try self.resolveInst(reduce.operand); - const operand_ty = self.typeOf(reduce.operand); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); - const scalar_ty = self.typeOfIndex(inst); - const llvm_scalar_ty = try o.lowerType(scalar_ty, .by_value); + const reduce = fg.air.instructions.items(.data)[@backingInt(inst)].reduce; + const operand = try fg.resolveInst(reduce.operand); + const operand_ty = fg.typeOf(reduce.operand); + const scalar_ty = fg.typeOfIndex(inst); switch (reduce.operation) { - .And, .Or, .Xor => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .And, .Or, .Xor => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .And => .@"vector.reduce.and", .Or => .@"vector.reduce.or", .Xor => .@"vector.reduce.xor", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), .Min, .Max => switch (scalar_ty.zigTypeTag(zcu)) { - .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .Min => if (scalar_ty.isSignedInt(zcu)) .@"vector.reduce.smin" else @@ -5946,29 +6167,29 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A else .@"vector.reduce.umax", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), - .float => if (intrinsicsAllowed(scalar_ty, target)) - return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) { + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), + .float => if (intrinsicsAllowed(.libc, scalar_ty, target)) + return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { .Min => .@"vector.reduce.fmin", .Max => .@"vector.reduce.fmax", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), else => unreachable, }, .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) { - .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .Add => .@"vector.reduce.add", .Mul => .@"vector.reduce.mul", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), - .float => if (intrinsicsAllowed(scalar_ty, target)) - return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) { + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), + .float => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) + return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { .Add => .@"vector.reduce.fadd", .Mul => .@"vector.reduce.fmul", else => unreachable, - }, &.{llvm_operand_ty}, &.{ switch (reduce.operation) { - .Add => try o.builder.fpValue(llvm_scalar_ty, -0.0), - .Mul => try o.builder.fpValue(llvm_scalar_ty, 1.0), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{ switch (reduce.operation) { + .Add => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), -0.0), + .Mul => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), 1.0), else => unreachable, }, operand }, ""), else => unreachable, @@ -5986,62 +6207,119 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A libcFloatPrefix(float_bits), libcFloatSuffix(float_bits), }), .Add => try o.builder.strtabStringFmt("__add{s}f3", .{ - compilerRtFloatAbbrev(float_bits), + compilerRtFloatAbbrev(target, float_bits), }), .Mul => try o.builder.strtabStringFmt("__mul{s}f3", .{ - compilerRtFloatAbbrev(float_bits), + compilerRtFloatAbbrev(target, float_bits), }), else => unreachable, }; - - const libc_fn = try o.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty); - const init_val = switch (llvm_scalar_ty) { - .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast( - @as(f16, switch (reduce.operation) { - .Min, .Max => std.math.nan(f16), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), - .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast( - @as(f80, switch (reduce.operation) { - .Min, .Max => std.math.nan(f80), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), - .i128 => try o.builder.intValue(.i128, @as(i128, @bitCast( - @as(f128, switch (reduce.operation) { - .Min, .Max => std.math.nan(f128), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), + const fn_info: Object.FuncInfo = .{ + .cc = target.cCallingConvention().?, + .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() }, + .return_type = scalar_ty.toIntern(), + }; + const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info); + const init = switch (float_bits) { else => unreachable, + 16 => try o.f16Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f16), + .Add => -0.0, + .Mul => 1.0, + }), + 32 => try o.f32Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f32), + .Add => -0.0, + .Mul => 1.0, + }), + 64 => try o.f64Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f64), + .Add => -0.0, + .Mul => 1.0, + }), + 80 => try o.f80Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f80), + .Add => -0.0, + .Mul => 1.0, + }), + 128 => try o.f128Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f128), + .Add => -0.0, + .Mul => 1.0, + }), }; - return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(zcu), init_val); + const iterations = operand_ty.vectorLen(zcu); + const is_by_ref = isByRef(operand_ty, zcu); + if (iterations > 1 and is_by_ref) { + const init_ref = try o.lowerConstRef(init, scalar_ty.abiAlignment(zcu).toLlvm()); + + const entry_block = fg.wip.cursor.block; + const loop_block = try fg.wip.block(2, "reduce.loop"); + const done_block = try fg.wip.block(1, "reduce.loop"); + + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const index = try fg.wip.phi(.i32, "reduce.index"); + const result = try fg.wip.phi(.ptr, "reduce.result"); + + const rhs_elem_ptr = try fg.ptraddScaled(operand, index.toValue(), scalar_ty.abiSize(zcu)); + const rhs_elem = try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal); + const next_result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result.toValue(), rhs_elem }); + + const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "reduce.next_index"); + index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip); + result.finish(&.{ init_ref.toValue(), next_result }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "reduce.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + return next_result; + } + var result = init.toValue(); + for (0..iterations) |index| { + const index_value = try o.builder.intValue(.i32, index); + const rhs_elem = if (is_by_ref) rhs_elem: { + const rhs_elem_ptr = try fg.ptraddConst(operand, index * scalar_ty.abiSize(zcu)); + break :rhs_elem try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal); + } else try fg.wip.extractElement(operand, index_value, "reduce.rhs_elem"); + result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result, rhs_elem }); + } + return result; } -fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { - const o = self.object; +fn airAggregateInit(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; const ip = &zcu.intern_pool; - const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl; - const result_ty = self.typeOfIndex(inst); + const ty_pl = fg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; + const result_ty = fg.typeOfIndex(inst); const len: usize = @intCast(result_ty.arrayLen(zcu)); - const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[ty_pl.payload..][0..len]); + const elements: []const Air.Inst.Ref = @ptrCast(fg.air.extra.items[ty_pl.payload..][0..len]); switch (result_ty.zigTypeTag(zcu)) { - .vector => { - const llvm_result_ty = try o.lowerType(result_ty, .by_value); + .vector => if (isByRef(result_ty, zcu)) { + const elem_ty = result_ty.childType(zcu); + const elem_size = elem_ty.abiSize(zcu); + const result_ptr = try fg.buildZigAlloca(result_ty, .none); + for (elements, 0..) |elem, elem_index| { + const elem_ptr = try fg.ptraddConst(result_ptr, elem_index * elem_size); + const llvm_elem = try fg.resolveInst(elem); + try fg.store(elem_ptr, .none, llvm_elem, elem_ty, .normal); + } + return result_ptr; + } else { + const llvm_result_ty = try o.lowerType(result_ty, .as_value); var vector = try o.builder.poisonValue(llvm_result_ty); - for (elements, 0..) |elem, i| { - const index_u32 = try o.builder.intValue(.i32, i); - const llvm_elem = try self.resolveInst(elem); - vector = try self.wip.insertElement(vector, llvm_elem, index_u32, ""); + for (elements, 0..) |elem, elem_index| { + const elem_index_val = try o.builder.intValue(.i32, elem_index); + const llvm_elem = try fg.resolveInst(elem); + vector = try fg.wip.insertElement(vector, llvm_elem, elem_index_val, ""); } return vector; }, @@ -6057,18 +6335,18 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde for (elements, struct_type.field_types.get(ip)) |elem, field_ty| { if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; - const non_int_val = try self.resolveInst(elem); + const non_int_val = try fg.resolveInst(elem); const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(zcu)); const small_int_ty = try o.builder.intType(ty_bit_size); const small_int_val = if (Type.fromInterned(field_ty).isPtrAtRuntime(zcu)) - try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") + try fg.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") else - try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); + try fg.wip.cast(.bitcast, non_int_val, small_int_ty, ""); const shift_rhs = try o.builder.intValue(int_ty, running_bits); const extended_int_val = - try self.wip.conv(.unsigned, small_int_val, int_ty, ""); - const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, ""); - running_int = try self.wip.bin(.@"or", running_int, shifted, ""); + try fg.wip.conv(.unsigned, small_int_val, int_ty, ""); + const shifted = try fg.wip.bin(.shl, extended_int_val, shift_rhs, ""); + running_int = try fg.wip.bin(.@"or", running_int, shifted, ""); running_bits += ty_bit_size; } return running_int; @@ -6078,19 +6356,19 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde // TODO in debug builds init to undef so that the padding will be 0xaa // even if we fully populate the fields. const struct_align = result_ty.abiAlignment(zcu); - const alloca_inst = try self.buildZigAlloca(result_ty, .none); + const alloca_inst = try fg.buildZigAlloca(result_ty, .none); for (elements, 0..) |elem, field_index| { if (result_ty.structFieldIsComptime(field_index, zcu)) continue; const field_ty = result_ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; const offset = result_ty.structFieldOffset(field_index, zcu); - const field_ptr = try self.ptraddConst(alloca_inst, offset); + const field_ptr = try fg.ptraddConst(alloca_inst, offset); const field_ptr_align = struct_align.offset(offset); - const llvm_field_val = try self.resolveInst(elem); + const llvm_field_val = try fg.resolveInst(elem); - try self.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal); + try fg.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal); } return alloca_inst; @@ -6099,21 +6377,21 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde .array => { assert(isByRef(result_ty, zcu)); - const alloca_inst = try self.buildZigAlloca(result_ty, .none); + const alloca_inst = try fg.buildZigAlloca(result_ty, .none); const array_info = result_ty.arrayInfo(zcu); const elem_size = array_info.elem_type.abiSize(zcu); for (elements, 0..) |elem, i| { - const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * i); - const llvm_elem = try self.resolveInst(elem); - try self.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal); + const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * i); + const llvm_elem = try fg.resolveInst(elem); + try fg.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal); } if (array_info.sentinel) |sent_val| { - const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * array_info.len); - const llvm_elem = try self.resolveValue(sent_val); - try self.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal); + const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * array_info.len); + const llvm_elem = try fg.resolveValue(sent_val); + try fg.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal); } return alloca_inst; @@ -6153,10 +6431,10 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const loaded_enum = ip.loadEnumType(tag_ty.toIntern()); const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, extra.field_index)) { .none => try o.builder.intConst( - try o.lowerType(.fromInterned(union_obj.enum_tag_type), .by_value), + try o.lowerType(.fromInterned(union_obj.enum_tag_type), .as_value), extra.field_index, // auto-numbered ), - else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .as_value), }; const tag_ptr = try self.ptraddConst(result_ptr, layout.tagOffset()); try self.store(tag_ptr, layout.tag_align, llvm_tag_val.toValue(), tag_ty, .normal); @@ -6218,7 +6496,7 @@ fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const inst_ty = self.typeOfIndex(inst); const operand = try self.resolveInst(ty_op.operand); - return self.wip.cast(.addrspacecast, operand, try self.object.lowerType(inst_ty, .by_value), ""); + return self.wip.cast(.addrspacecast, operand, try self.object.lowerType(inst_ty, .as_value), ""); } fn workIntrinsic( @@ -6370,7 +6648,7 @@ fn load( }; if (isByRef(load_ty, zcu)) { - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const result_ptr = try fg.buildZigAlloca(load_ty, .none); _ = try fg.wip.callMemCpy( result_ptr, @@ -6384,10 +6662,10 @@ fn load( return result_ptr; } - const llvm_memory_ty = try o.lowerType(load_ty, .in_memory); - const llvm_value_ty = try o.lowerType(load_ty, .by_value); + const llvm_access_ty = try o.lowerType(load_ty, .memory_access); + const llvm_value_ty = try o.lowerType(load_ty, .as_value); - if (llvm_memory_ty != llvm_value_ty) { + if (llvm_access_ty != llvm_value_ty) { assert(load_ty.isAbiInt(zcu)); // `load_ty` is an integer type with padding bits. In theory, we shouldn't need any special // handling for these, as LLVM's documented semantics are a valid implementation of Zig's @@ -6401,7 +6679,7 @@ fn load( // // Therefore, we handle these memory accesses specially: in this case we will actually load // the next-largest "natural" integer type and then truncate to `load_ty`. - const loaded = try fg.wip.load(access_kind, llvm_memory_ty, ptr, llvm_ptr_align, ""); + const loaded = try fg.wip.load(access_kind, llvm_access_ty, ptr, llvm_ptr_align, ""); // For packed structs, current Zig semantics don't really allow us to make the padding bits // well-defined. This should be solved once https://github.com/ziglang/zig/issues/24061 is // implemented, but until then, do a normal trunc for packed types. @@ -6443,7 +6721,7 @@ fn store( }; if (isByRef(elem_ty, zcu)) { - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); _ = try fg.wip.callMemCpy( ptr, llvm_ptr_align, @@ -6456,45 +6734,31 @@ fn store( return; } - assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .by_value)); + assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .as_value)); - const llvm_memory_ty = try o.lowerType(elem_ty, .in_memory); - const llvm_value_ty = try o.lowerType(elem_ty, .by_value); + const llvm_access_ty = try o.lowerType(elem_ty, .memory_access); + const llvm_value_ty = try o.lowerType(elem_ty, .as_value); - if (llvm_memory_ty != llvm_value_ty) { + if (llvm_access_ty != llvm_value_ty) { assert(elem_ty.isAbiInt(zcu)); // `elem_ty` is an integer type with padding bits, so we need to handle it specially---see // the corresponding comment in `FuncGen.load` for more details. const extended = try fg.wip.cast(switch (elem_ty.intInfo(zcu).signedness) { .unsigned => .zext, .signed => .sext, - }, elem, llvm_memory_ty, ""); - _ = try fg.wip.storeAtomic( - access_kind, - extended, - ptr, - fg.sync_scope, - .none, - llvm_ptr_align, - ); + }, elem, llvm_access_ty, ""); + _ = try fg.wip.store(access_kind, extended, ptr, llvm_ptr_align); return; } // `elem_ty` is a simple by-val type which requires no special handling. - _ = try fg.wip.storeAtomic( - access_kind, - elem, - ptr, - fg.sync_scope, - .none, - llvm_ptr_align, - ); + _ = try fg.wip.store(access_kind, elem, ptr, llvm_ptr_align); } fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void { const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; const o = fg.object; - const usize_ty = try o.lowerType(.usize, .by_value); + const usize_ty = try o.lowerType(.usize, .as_value); const zero = try o.builder.intValue(usize_ty, 0); const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED); const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, ""); @@ -6516,7 +6780,7 @@ fn valgrindClientRequest( const target = zcu.getTarget(); if (!target_util.hasValgrindSupport(target, .stage2_llvm)) return default_value; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const usize_align = Type.usize.abiAlignment(zcu).toLlvm(); const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); @@ -6650,13 +6914,14 @@ fn typeOfIndex(fg: *FuncGen, inst: Air.Inst.Index) Type { const ParamTypeIterator = struct { object: *Object, - fn_info: InternPool.Key.FuncType, + cc: std.lang.CallingConvention, + param_types: []const InternPool.Index, zig_index: u32, llvm_index: u32, types_len: u32, types_buffer: [8]Builder.Type, offsets_buffer: [9]u64, - byval_attr: bool, + byval_attr: ?Object.Byval, const Lowering = union(enum) { no_bits, @@ -6672,88 +6937,78 @@ const ParamTypeIterator = struct { }; pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering { - if (it.zig_index >= it.fn_info.param_types.len) return null; - const ip = &it.object.zcu.intern_pool; - const ty = it.fn_info.param_types.get(ip)[it.zig_index]; - it.byval_attr = false; + if (it.zig_index >= it.param_types.len) return null; + const ty = it.param_types[it.zig_index]; + it.byval_attr = null; return nextInner(it, Type.fromInterned(ty)); } /// `airCall` uses this instead of `next` so that it can take into account variadic functions. - fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering { - const ip = &it.object.zcu.intern_pool; - if (it.zig_index >= it.fn_info.param_types.len) { - if (it.zig_index >= args.len) { + fn nextCall(it: *ParamTypeIterator, arg_types: []const InternPool.Index) Allocator.Error!?Lowering { + if (it.zig_index >= it.param_types.len) { + if (it.zig_index >= arg_types.len) { return null; } else { - return nextInner(it, fg.typeOf(args[it.zig_index])); + return nextInner(it, .fromInterned(arg_types[it.zig_index])); } } else { - return nextInner(it, Type.fromInterned(it.fn_info.param_types.get(ip)[it.zig_index])); + return nextInner(it, .fromInterned(it.param_types[it.zig_index])); } } fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { const zcu = it.object.zcu; - const target = zcu.getTarget(); - + ty.assertHasLayout(zcu); if (!ty.hasRuntimeBits(zcu)) { it.zig_index += 1; return .no_bits; } - switch (it.fn_info.cc) { + switch (it.cc) { .@"inline" => unreachable, .auto => { it.zig_index += 1; it.llvm_index += 1; + + // Match the c calling convention in some cases to avoid llvm bugs. + const target = zcu.getTarget(); + if (target.cpu.arch == .x86_64 and ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type) return switch (ty.vectorLen(zcu)) { + 0 => .no_bits, + 1...32 => .abi_sized_int, + 33...64 => { + it.types_buffer[0..1].* = .{.double}; + it.offsets_buffer[0..2].* = .{ 0, 8 }; + it.types_len = 1; + return .multiple_llvm_types; + }, + else => .byval, + }; + if (ty.isSlice(zcu) or (ty.zigTypeTag(zcu) == .optional and ty.optionalChild(zcu).isSlice(zcu) and !ty.ptrAllowsZero(zcu))) { it.llvm_index += 1; return .slice; - } else if (isByRef(ty, zcu)) { - return .byref; - } else if (target.cpu.arch.isX86() and - !target.cpu.has(.x86, .avx512f) and - ty.totalVectorBits(zcu) >= 512) - { - // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns - // "512-bit vector arguments require 'avx512f' for AVX512" - return .byref; - } else { - return .byval; } + if (isByRef(ty, zcu)) return .byref; + return .byval; }, .async => { @panic("TODO implement async function lowering in the LLVM backend"); }, - .x86_64_sysv, .x86_64_x32 => return it.nextSystemV(ty), - .x86_64_win => return it.nextWin64(ty), - .x86_stdcall => { - it.zig_index += 1; - it.llvm_index += 1; - - if (isScalar(zcu, ty)) { - return .byval; - } else { - it.byval_attr = true; - return .byref; - } - }, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => { it.zig_index += 1; it.llvm_index += 1; switch (aarch64_c_abi.classifyType(ty, zcu)) { .memory => return .byref_mut, - .float_array => |len| return Lowering{ .float_array = len }, + .float_array => |len| return .{ .float_array = len }, .byval => return .byval, .integer => { - it.types_len = 1; it.types_buffer[0..1].* = .{.i64}; it.offsets_buffer[0..2].* = .{ 0, 8 }; + it.types_len = 1; return .multiple_llvm_types; }, - .double_integer => return Lowering{ .i64_array = 2 }, + .double_integer => return .{ .i64_array = 2 }, } }, .arm_aapcs, .arm_aapcs_vfp => { @@ -6761,26 +7016,101 @@ const ParamTypeIterator = struct { it.llvm_index += 1; switch (arm_c_abi.classifyType(ty, zcu, .arg)) { .memory => { - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, .byval => return .byval, - .i32_array => |size| return Lowering{ .i32_array = size }, - .i64_array => |size| return Lowering{ .i64_array = size }, + .i32_array => |size| return .{ .i32_array = size }, + .i64_array => |size| return .{ .i64_array = size }, } }, + .loongarch32_ilp32, .loongarch64_lp64 => switch (loongarch_c_abi.classifyType(ty, zcu)) { + .ignored => { + it.zig_index += 1; + return .no_bits; + }, + .gar, .far => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + .member => |member_ty| { + it.types_buffer[0..1].* = .{ + try it.object.lowerType(member_ty, .as_value), + }; + it.offsets_buffer[0..2].* = .{ 0, member_ty.abiSize(zcu) }; + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + }, + .member_pair => |member_tys| { + it.types_buffer[0..2].* = .{ + try it.object.lowerType(member_tys[0], .as_value), + try it.object.lowerType(member_tys[1], .as_value), + }; + const first_size = member_tys[0].abiSize(zcu); + const second_size = member_tys[0].abiSize(zcu); + it.offsets_buffer[0..3].* = .{ 0, first_size, first_size + second_size }; + it.types_len = 2; + it.zig_index += 1; + it.llvm_index += 2; + return .multiple_llvm_types; + }, + .memory_gar => { + switch (it.cc) { + else => unreachable, + .loongarch32_ilp32 => { + it.types_buffer[0..1].* = .{.i32}; + it.offsets_buffer[0..2].* = .{ 0, 4 }; + }, + .loongarch64_lp64 => { + it.types_buffer[0..1].* = .{.i64}; + it.offsets_buffer[0..2].* = .{ 0, 8 }; + }, + } + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + }, + .memory_gar_pair => { + it.zig_index += 1; + it.llvm_index += 1; + return switch (it.cc) { + else => unreachable, + .loongarch32_ilp32 => .{ .i32_array = 2 }, + .loongarch64_lp64 => .{ .i64_array = 2 }, + }; + }, + .address => { + it.zig_index += 1; + it.llvm_index += 1; + return .byref; + }, + }, .mips_o32 => { it.zig_index += 1; it.llvm_index += 1; switch (mips_c_abi.classifyType(ty, zcu, .arg)) { .memory => { - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, .byval => return .byval, - .i32_array => |size| return Lowering{ .i32_array = size }, + .i32_array => |size| return .{ .i32_array = size }, } }, + .powerpc64_elf_v2 => { + it.zig_index += 1; + it.llvm_index += 1; + if (isByRef(ty, zcu)) return switch (ty.abiSize(zcu)) { + 1...8 => .abi_sized_int, + 9...64 => |abi_size| .{ .i64_array = @intCast(@divCeil(abi_size, 8)) }, + else => .byref, + }; + return .byval; // TODO + }, .riscv64_lp64, .riscv32_ilp32 => { it.zig_index += 1; it.llvm_index += 1; @@ -6788,7 +7118,7 @@ const ParamTypeIterator = struct { .memory => return .byref_mut, .byval => return .byval, .integer => return .abi_sized_int, - .double_integer => return Lowering{ .i64_array = 2 }, + .double_integer => return .{ .i64_array = 2 }, .fields => { it.types_len = 0; var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct| @@ -6798,7 +7128,7 @@ const ParamTypeIterator = struct { while (field_it.next()) |field_index| { const field_ty = ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; - it.types_buffer[it.types_len] = try it.object.lowerType(field_ty, .by_value); + it.types_buffer[it.types_len] = try it.object.lowerType(field_ty, .as_value); it.offsets_buffer[it.types_len] = ty.structFieldOffset(field_index, zcu); it.types_len += 1; } @@ -6808,6 +7138,24 @@ const ParamTypeIterator = struct { }, } }, + .s390x_sysv, .s390x_sysv_vx => { + it.zig_index += 1; + switch (s390x_c_abi.classifyType(ty, .arg, zcu)) { + .none => return .no_bits, + .double_or_float, .vector, .simple => { + it.llvm_index += 1; + return .byval; + }, + .simple_aggregate => { + it.llvm_index += 1; + return .abi_sized_int; + }, + .pointer => { + it.llvm_index += 1; + return .byref_mut; + }, + } + }, .wasm_mvp => switch (wasm_c_abi.classifyType(ty, zcu)) { .direct => |scalar_ty| { if (isScalar(zcu, ty)) { @@ -6815,21 +7163,80 @@ const ParamTypeIterator = struct { it.llvm_index += 1; return .byval; } else { - it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty, .by_value)}; + it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty, .as_value)}; it.offsets_buffer[0..2].* = .{ 0, scalar_ty.abiSize(zcu) }; it.types_len = 1; - it.llvm_index += 1; it.zig_index += 1; + it.llvm_index += 1; return .multiple_llvm_types; } }, .indirect => { it.zig_index += 1; it.llvm_index += 1; - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, }, + .x86_stdcall => { + it.zig_index += 1; + it.llvm_index += 1; + + if (isScalar(zcu, ty)) { + return .byval; + } else { + it.byval_attr = .{}; + return .byref; + } + }, + .x86_sysv, .x86_win, .x86_mingw => { + if (isByRef(ty, zcu)) { + var items_buf: [1]codegen.FlattenedItem = undefined; + if (codegen.flattenType(&items_buf, ty, zcu, .{ + .allow_arrays = false, + })) |items| one_float: { + if (items.len != 1 or items[0].offset != 0) break :one_float; + const item_ty = items[0].type orelse break :one_float; + if (!item_ty.isRuntimeFloat()) break :one_float; + it.types_buffer[0..1].*, it.offsets_buffer[0..2].* = + switch (item_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 32 => .{ .{.float}, .{ 0, 4 } }, + 64 => .{ .{.double}, .{ 0, 8 } }, + 16, 80, 128 => break :one_float, + }; + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + } + it.zig_index += 1; + it.llvm_index += 1; + it.byval_attr = .{ .alignment = .@"4" }; + return .byref; + } + if (ty.isAbiInt(zcu)) switch (ty.intInfo(zcu).bits) { + else => unreachable, + 8, 16, 32, 64 => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + 128 => { + it.types_buffer[0..2].* = .{ .i64, .i64 }; + it.offsets_buffer[0..3].* = .{ 0, 8, 16 }; + it.types_len = 2; + it.zig_index += 1; + it.llvm_index += 2; + return .multiple_llvm_types; + }, + }; + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + .x86_64_sysv, .x86_64_x32 => return try it.next_x86_64_sysv(ty), + .x86_64_win => return it.next_x86_64_win(ty), // TODO investigate other callconvs else => { it.zig_index += 1; @@ -6839,7 +7246,7 @@ const ParamTypeIterator = struct { } } - fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering { + fn next_x86_64_win(it: *ParamTypeIterator, ty: Type) Lowering { const zcu = it.object.zcu; switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget(), .arg)) { .integer => { @@ -6880,119 +7287,114 @@ const ParamTypeIterator = struct { } } - fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { - const zcu = it.object.zcu; - const ip = &zcu.intern_pool; - ty.assertHasLayout(zcu); - const classes = x86_64_abi.classifySystemV(ty, zcu, zcu.getTarget(), .arg); - if (classes[0] == .memory) { - it.zig_index += 1; - it.llvm_index += 1; - it.byval_attr = true; - return .byref; - } - if (isScalar(zcu, ty)) { - it.zig_index += 1; - it.llvm_index += 1; - return .byval; - } - var types_index: u32 = 0; - var offset: u64 = 0; - for (classes) |class| { - switch (class) { - .integer => { - it.types_buffer[types_index] = .i64; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .sse => { - it.types_buffer[types_index] = .double; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .sseup => { - if (it.types_buffer[types_index - 1] == .double) { - it.types_buffer[types_index - 1] = .fp128; - } else { - it.types_buffer[types_index] = .double; - it.offsets_buffer[types_index] = offset; - types_index += 1; + fn next_x86_64_sysv(it: *ParamTypeIterator, ty: Type) Allocator.Error!Lowering { + const o = it.object; + const zcu = o.zcu; + const target = zcu.getTarget(); + const classes = x86_64_abi.classifySystemV(ty, zcu, target, .arg); + var types_len: u32 = 0; + const classes_len = for (classes, 0..) |class, class_index| switch (class) { + .integer => { + it.types_buffer[types_len] = try o.builder.intType(@min(8 * ty.abiSize(zcu) - 64 * class_index, 64)); + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .sse => { + it.types_buffer[types_len] = .double; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .sseup => { + if (it.types_buffer[types_len - 1] == .double) { + if (ty.isVector(zcu)) { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; } - }, - .float => { - it.types_buffer[types_index] = .float; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .float_combine => { - it.types_buffer[types_index] = try it.object.builder.vectorType(.normal, 2, .float); - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .x87 => { - it.zig_index += 1; - it.llvm_index += 1; - it.byval_attr = true; - return .byref; - }, - .x87up => unreachable, - .none => break, - .memory => unreachable, // handled above - .win_i128 => unreachable, // windows only - .bool_vector_mask, - .integer_per_element, - .sse_per_element, - .sse_sse_x87_per_qword, - .sse_per_xword, - .sse_per_yword, - .sse_per_zword, - => unreachable, // vectors already handled by `isScalar` above - } - offset += 8; - } - const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); - if (first_non_integer == null or classes[first_non_integer.?] == .none) { - assert(first_non_integer orelse classes.len == types_index); - if (types_index == 1) { + it.types_buffer[types_len - 1] = .fp128; + } else { + it.types_buffer[types_len] = .double; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + } + }, + .float => { + it.types_buffer[types_len] = .float; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .float_combine => { + it.types_buffer[types_len] = try it.object.builder.vectorType(.normal, 2, .float); + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .x87 => { it.zig_index += 1; it.llvm_index += 1; - return .abi_sized_int; - } - if (it.llvm_index + types_index > 6) { + it.byval_attr = .{}; + return .byref; + }, + .x87up => unreachable, + .none => break class_index, + .memory => { + it.zig_index += 1; + it.llvm_index += 1; + it.byval_attr = .{}; + return .byref; + }, + .win_i128 => unreachable, // windows only + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + } else classes.len; + if (types_len > 1) { + if (it.llvm_index + classes_len > 6) { it.zig_index += 1; it.llvm_index += 1; - it.byval_attr = true; + it.byval_attr = .{}; return .byref; } - switch (ip.indexToKey(ty.toIntern())) { - .struct_type => { - const size = ty.abiSize(zcu); - assert(@divCeil(size, 8) == types_index); - if (size % 8 > 0) { - it.types_buffer[types_index - 1] = - try it.object.builder.intType(@intCast(size % 8 * 8)); - } - }, - else => {}, + } else if (!isByRef(ty, zcu)) { + const llvm_ty = try o.lowerType(ty, .as_value); + if (it.types_buffer[0] == llvm_ty or + (it.types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder))) + { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; } } - it.offsets_buffer[types_index] = offset; - it.types_len = types_index; - it.llvm_index += types_index; + it.offsets_buffer[types_len] = 8 * classes_len; + it.types_len = types_len; + it.llvm_index += types_len; it.zig_index += 1; return .multiple_llvm_types; } }; -pub fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTypeIterator { +pub fn iterateParamTypes( + object: *Object, + cc: std.lang.CallingConvention, + param_types: []const InternPool.Index, +) ParamTypeIterator { return .{ .object = object, - .fn_info = fn_info, + .cc = cc, + .param_types = param_types, .zig_index = 0, .llvm_index = 0, .types_len = undefined, .types_buffer = undefined, .offsets_buffer = undefined, - .byval_attr = false, + .byval_attr = null, }; } @@ -7017,54 +7419,68 @@ pub const FnReturnStrat = union(enum) { /// In order to support the C calling convention, some return types need to be lowered /// completely differently in the function prototype to honor the C ABI, and then /// be effectively bitcasted to the actual return type. -pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +pub fn fnReturnStrat(o: *Object, cc: std.lang.CallingConvention, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ret_ty: Type = .fromInterned(fn_info.return_type); ret_ty.assertHasLayout(zcu); if (!ret_ty.hasRuntimeBits(zcu)) return .void; - switch (fn_info.cc) { + return switch (cc) { .@"inline" => unreachable, .auto => { - if (isByRef(ret_ty, zcu)) return .sret; - + // Match the c calling convention in some cases to avoid llvm bugs. const target = zcu.getTarget(); - if (target.cpu.arch.isX86() and - !target.cpu.has(.x86, .avx512f) and - ret_ty.totalVectorBits(zcu) >= 512) - { - // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns - // "512-bit vector arguments require 'avx512f' for AVX512" - return .sret; - } - - return .by_val; + if (target.cpu.arch == .x86_64 and ret_ty.isVector(zcu) and ret_ty.childType(zcu).toIntern() == .bool_type) return switch (ret_ty.vectorLen(zcu)) { + 0 => .void, + 1...8 => .{ .mem_cast = .i8 }, + 9...16 => .{ .mem_cast = .i16 }, + 17...32 => .{ .mem_cast = .i32 }, + 33...64 => .{ .mem_cast = .double }, + else => .by_val, + }; + return if (isByRef(ret_ty, zcu)) .sret else .by_val; }, - .x86_64_sysv, .x86_64_x32 => return lowerSystemVFnRetTy(o, fn_info), - .x86_64_win => return lowerWin64FnRetTy(o, fn_info), - .x86_stdcall => if (isScalar(zcu, ret_ty)) { - assert(!isByRef(ret_ty, zcu)); - return .by_val; - } else return .sret, - .x86_fastcall => return lowerX86FastcallFnRetTy(o, zcu, ret_ty), - .x86_sysv, .x86_win => return if (isByRef(ret_ty, zcu)) .sret else .by_val, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(ret_ty, zcu)) { - .memory => return .sret, - .float_array, .byval => return .forceByVal(o, ret_ty), - .integer => return .{ .mem_cast = .i64 }, - .double_integer => return .{ .mem_cast = try o.builder.arrayType(2, .i64) }, + .memory => .sret, + .float_array, .byval => .forceByVal(o, ret_ty), + .integer => .{ .mem_cast = .i64 }, + .double_integer => .{ .mem_cast = try o.builder.arrayType(2, .i64) }, }, .arm_aapcs, .arm_aapcs_vfp => switch (arm_c_abi.classifyType(ret_ty, zcu, .ret)) { - .memory, .i64_array => return .sret, - .i32_array => |len| return if (len == 1) .{ .mem_cast = .i32 } else .sret, - .byval => return .forceByVal(o, ret_ty), + .memory, .i64_array => .sret, + .i32_array => |len| if (len == 1) .{ .mem_cast = .i32 } else .sret, + .byval => .forceByVal(o, ret_ty), + }, + .loongarch32_ilp32, .loongarch64_lp64 => switch (loongarch_c_abi.classifyType(ret_ty, zcu)) { + .ignored => .void, + .gar, .far => .by_val, + .member => |member_ty| .{ .mem_cast = try o.lowerType(member_ty, .as_value) }, + .member_pair => |member_tys| .{ .mem_cast = try o.builder.structType(.normal, &.{ + try o.lowerType(member_tys[0], .as_value), + try o.lowerType(member_tys[1], .as_value), + }) }, + .memory_gar => .{ .mem_cast = switch (cc) { + else => unreachable, + .loongarch32_ilp32 => .i32, + .loongarch64_lp64 => .i64, + } }, + .memory_gar_pair => .{ .mem_cast = try o.builder.arrayType(2, switch (cc) { + else => unreachable, + .loongarch32_ilp32 => .i32, + .loongarch64_lp64 => .i64, + }) }, + .address => .sret, }, .mips_o32 => switch (mips_c_abi.classifyType(ret_ty, zcu, .ret)) { - .memory, .i32_array => return .sret, - .byval => return .forceByVal(o, ret_ty), + .memory, .i32_array => .sret, + .byval => .forceByVal(o, ret_ty), }, + .powerpc64_elf_v2 => if (isByRef(ret_ty, zcu)) switch (ret_ty.abiSize(zcu)) { + 1...8 => .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, + 9...16 => .{ .mem_cast = try o.builder.structType(.normal, &.{ .i64, .i64 }) }, + else => .sret, + } else .by_val, // TODO .riscv64_lp64, .riscv32_ilp32 => switch (riscv_c_abi.classifyType(ret_ty, zcu)) { - .memory => return .sret, - .integer => return .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, + .memory => .sret, + .integer => .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, .double_integer => { const integer: Builder.Type = switch (zcu.getTarget().cpu.arch) { .riscv64, .riscv64be => .i64, @@ -7073,34 +7489,78 @@ pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err }; return .{ .mem_cast = try o.builder.structType(.normal, &.{ integer, integer }) }; }, - .byval => return .forceByVal(o, ret_ty), + .byval => .forceByVal(o, ret_ty), .fields => { var types_len: usize = 0; var types: [8]Builder.Type = undefined; for (0..ret_ty.structFieldCount(zcu)) |field_index| { const field_ty = ret_ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; - types[types_len] = try o.lowerType(field_ty, .by_value); + types[types_len] = try o.lowerType(field_ty, .as_value); types_len += 1; } return .{ .mem_cast = try o.builder.structType(.normal, types[0..types_len]) }; }, }, + .s390x_sysv, .s390x_sysv_vx => switch (s390x_c_abi.classifyType(ret_ty, .ret, zcu)) { + .none => .void, + .double_or_float, .vector, .simple => .by_val, + .simple_aggregate => unreachable, + .pointer => .sret, + }, .wasm_mvp => switch (wasm_c_abi.classifyType(ret_ty, zcu)) { .direct => |scalar_ty| if (scalar_ty.toIntern() == ret_ty.toIntern()) { assert(!isByRef(ret_ty, zcu)); return .by_val; - } else { - return .{ .mem_cast = try o.lowerType(scalar_ty, .by_value) }; - }, - .indirect => return .sret, + } else .{ .mem_cast = try o.lowerType(scalar_ty, .as_value) }, + .indirect => .sret, }, + .x86_stdcall => if (isScalar(zcu, ret_ty)) { + assert(!isByRef(ret_ty, zcu)); + return .by_val; + } else .sret, + .x86_fastcall => fnReturnStrat_x86_fastcall(o, zcu, ret_ty), + .x86_sysv, .x86_win, .x86_mingw => if (isByRef(ret_ty, zcu)) { + switch (cc) { + else => unreachable, + .x86_sysv => return .sret, + .x86_win => {}, + .x86_mingw => { + var items_buf: [1]codegen.FlattenedItem = undefined; + if (codegen.flattenType(&items_buf, ret_ty, zcu, .{})) |items| one_float: { + if (items.len != 1 or items[0].offset != 0) break :one_float; + const item_ty = items[0].type orelse break :one_float; + if (!item_ty.isRuntimeFloat()) break :one_float; + return .{ .mem_cast = switch (item_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16 => .half, + 32 => .float, + 64 => .double, + 80, 128 => break :one_float, + } }; + } + }, + } + return switch (ret_ty.abiSize(zcu)) { + 0 => .void, + 1 => .{ .mem_cast = .i8 }, + 2 => .{ .mem_cast = .i16 }, + 4 => .{ .mem_cast = .i32 }, + 8 => .{ .mem_cast = .i64 }, + else => .sret, + }; + } else if (ret_ty.isAbiInt(zcu) and ret_ty.intInfo(zcu).bits > 64) + .sret + else + .by_val, + .x86_64_sysv, .x86_64_x32 => fnReturnStrat_x86_64_sysv(o, ret_ty), + .x86_64_win => fnReturnStrat_x86_64_win(o, ret_ty), // TODO investigate other callconvs - else => return .forceByVal(o, ret_ty), - } + else => .forceByVal(o, ret_ty), + }; } -fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_fastcall(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat { if (isScalar(zcu, ty)) { assert(!isByRef(ty, zcu)); return .by_val; @@ -7115,9 +7575,8 @@ fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnRe return .sret; } -fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_64_win(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ret_ty = Type.fromInterned(fn_info.return_type); switch (x86_64_abi.classifyWindows(ret_ty, zcu, zcu.getTarget(), .ret)) { .integer => if (isScalar(zcu, ret_ty)) { assert(!isByRef(ret_ty, zcu)); @@ -7150,78 +7609,65 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err } } -fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_64_sysv(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ip = &zcu.intern_pool; - const ret_ty = Type.fromInterned(fn_info.return_type); - if (isScalar(zcu, ret_ty)) { - assert(!isByRef(ret_ty, zcu)); - return .by_val; - } const classes = x86_64_abi.classifySystemV(ret_ty, zcu, zcu.getTarget(), .ret); - var types_index: u32 = 0; var types_buffer: [8]Builder.Type = undefined; - for (classes) |class| { - switch (class) { - .integer => { - types_buffer[types_index] = .i64; - types_index += 1; - }, - .sse => { - types_buffer[types_index] = .double; - types_index += 1; - }, - .sseup => { - if (types_buffer[types_index - 1] == .double) { - types_buffer[types_index - 1] = .fp128; - } else { - types_buffer[types_index] = .double; - types_index += 1; - } - }, - .float => { - types_buffer[types_index] = .float; - types_index += 1; - }, - .float_combine => { - types_buffer[types_index] = try o.builder.vectorType(.normal, 2, .float); - types_index += 1; - }, - .x87 => { - if (types_index != 0 or classes[2] != .none) return .sret; - types_buffer[types_index] = .x86_fp80; - types_index += 1; - }, - .x87up => continue, - .none => break, - .memory => return .sret, - .win_i128 => unreachable, // windows only - .bool_vector_mask, - .integer_per_element, - .sse_per_element, - .sse_sse_x87_per_qword, - .sse_per_xword, - .sse_per_yword, - .sse_per_zword, - => unreachable, // vectors already handled by `isScalar` above - } + var types_len: u32 = 0; + for (classes, 0..) |class, class_index| switch (class) { + .integer => { + types_buffer[types_len] = try o.builder.intType(@min(8 * ret_ty.abiSize(zcu) - 64 * class_index, 64)); + types_len += 1; + }, + .sse => { + types_buffer[types_len] = .double; + types_len += 1; + }, + .sseup => { + if (types_buffer[types_len - 1] == .double) { + if (ret_ty.isVector(zcu)) return .by_val; + types_buffer[types_len - 1] = .fp128; + } else { + types_buffer[types_len] = .double; + types_len += 1; + } + }, + .float => { + types_buffer[types_len] = .float; + types_len += 1; + }, + .float_combine => { + types_buffer[types_len] = try o.builder.vectorType(.normal, 2, .float); + types_len += 1; + }, + .x87 => { + if (types_len > 0 or classes[2] != .none) return .sret; + types_buffer[types_len] = .x86_fp80; + types_len += 1; + }, + .x87up => continue, + .none => break, + .memory => return if (ret_ty.isVector(zcu)) .by_val else .sret, + .win_i128 => unreachable, // windows only + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => return .by_val, + }; + if (types_len > 1) return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_len]) }; + if (!isByRef(ret_ty, zcu)) { + const llvm_ty = try o.lowerType(ret_ty, .as_value); + if (types_buffer[0] == llvm_ty) return .by_val; + if (types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder)) return .by_val; + if (types_buffer[0] == .double and llvm_ty.isVector(&o.builder) and + llvm_ty.vectorLen(&o.builder) == 1 and + llvm_ty.scalarType(&o.builder) == .double) return .by_val; } - const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); - if (first_non_integer == null or classes[first_non_integer.?] == .none) { - assert(first_non_integer orelse classes.len == types_index); - switch (ip.indexToKey(ret_ty.toIntern())) { - .struct_type => { - const size = ret_ty.abiSize(zcu); - assert(@divCeil(size, 8) == types_index); - if (size % 8 > 0) { - types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); - } - }, - else => {}, - } - if (types_index == 1) return .{ .mem_cast = types_buffer[0] }; - } - return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_index]) }; + return .{ .mem_cast = types_buffer[0] }; } /// This function deliberately does not handle `_BitInt` because it typically @@ -7234,15 +7680,22 @@ pub fn ccAbiPromoteInt(cc: std.lang.CallingConvention, zcu: *Zcu, ty: Type) ?std else => {}, } - const ty_tag = ty.zigTypeTag(zcu); - const int_info = switch (ty_tag) { - .bool => Type.u1.intInfo(zcu), - else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return null, - }; - - assert(int_info.bits == 0 or (int_info.bits == 1 and ty_tag == .bool) or std.math.isPowerOfTwo(int_info.bits)); - const target = zcu.getTarget(); + const int_info: std.lang.Type.Int = if (ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (ty.isAbiInt(zcu)) + ty.intInfo(zcu) + else if (ty.isRuntimeFloat()) switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => return null, + .soft => .{ .signedness = .unsigned, .bits = bits }, + }, + 80, 128 => return null, + } else return null; + + assert(int_info.bits == 0 or (int_info.bits == 1 and ty.toIntern() == .bool_type) or std.math.isPowerOfTwo(int_info.bits)); + return switch (target.cpu.arch) { .aarch64, .aarch64_be, @@ -7338,15 +7791,26 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { .void, .bool, .int, - .float, .pointer, .error_set, .@"fn", .@"enum", - .vector, .@"anyframe", => false, + .float, .vector => { + const target = zcu.getTarget(); + const scalar_ty = ty.scalarType(zcu); + return if (scalar_ty.isRuntimeFloat()) switch (scalar_ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => false, + 80, 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => false, + .soft => true, + }, + } else false; + }, + .array, .frame, => ty.hasRuntimeBits(zcu), @@ -7392,7 +7856,7 @@ fn getAtomicAbiType(fg: *const FuncGen, ty: Type, is_rmw_xchg: bool) Allocator.E fn ptraddConst(fg: *FuncGen, ptr: Builder.Value, offset: u64) Allocator.Error!Builder.Value { if (offset == 0) return ptr; const o = fg.object; - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const offset_val = try o.builder.intValue(llvm_usize_ty, offset); return fg.wip.gep(.inbounds, .i8, ptr, &.{offset_val}, ""); } @@ -7407,12 +7871,19 @@ fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u return fg.wip.gep(.inbounds, llvm_scale_ty, ptr, &.{index}, ""); } -fn compilerRtIntBits(bits: u16) ?u16 { - inline for (.{ 32, 64, 128 }) |b| { - if (bits <= b) { - return b; - } - } +fn compilerRtPromoteInt(int_info: InternPool.Key.IntType) ?Type { + if (int_info.bits <= 32) return switch (int_info.signedness) { + .signed => .i32, + .unsigned => .u32, + }; + if (int_info.bits <= 64) return switch (int_info.signedness) { + .signed => .i64, + .unsigned => .u64, + }; + if (int_info.bits <= 128) return switch (int_info.signedness) { + .signed => .i128, + .unsigned => .u128, + }; return null; } @@ -7471,13 +7942,21 @@ fn appendConstraints( } /// LLVM does not support all relevant intrinsics for all targets, so we -/// may need to manually generate a compiler-rt call. -fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool { - return switch (scalar_ty.toIntern()) { - .f16_type => llvm.backendSupportsF16(target), - .f80_type => (target.cTypeBitSize(.longdouble) == 80) and llvm.backendSupportsF80(target), - .f128_type => (target.cTypeBitSize(.longdouble) == 128) and llvm.backendSupportsF128(target), - else => true, +/// may need to manually generate a compiler-rt call using a soft type. +fn intrinsicsAllowed(kind: enum { compiler_rt, libc }, scalar_ty: Type, target: *const std.Target) bool { + if (!scalar_ty.isRuntimeFloat()) return true; + const bits = scalar_ty.floatBits(target); + // Since upstream musl/msvc do not actually define the *f128 functions, llvm decides + // that it is a much better idea to just emit a call to the entirely wrong function as + // a fallback. We wouldn't want any linker errors when trying to perform an operation + // that isn't actually implemented anywhere, now would we! + if (bits == 128 and target.cpu.arch.isX86() and !target.abi.isGnu()) return switch (kind) { + .compiler_rt => true, + .libc => false, + }; + return switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => true, + .soft => false, }; } @@ -7823,12 +8302,14 @@ const Builder = std.zig.llvm.Builder; const assert = std.debug.assert; const math = std.math; -const x86_64_abi = @import("../x86_64/abi.zig"); -const wasm_c_abi = @import("../wasm/abi.zig"); const aarch64_c_abi = @import("../aarch64/abi.zig"); const arm_c_abi = @import("../arm/abi.zig"); -const riscv_c_abi = @import("../riscv64/abi.zig"); +const loongarch_c_abi = @import("../loongarch/abi.zig"); const mips_c_abi = @import("../mips/abi.zig"); +const riscv_c_abi = @import("../riscv64/abi.zig"); +const s390x_c_abi = @import("../s390x/abi.zig"); +const wasm_c_abi = @import("../wasm/abi.zig"); +const x86_64_abi = @import("../x86_64/abi.zig"); const Zcu = @import("../../Zcu.zig"); const Air = @import("../../Air.zig"); diff --git a/src/codegen/loongarch/abi.zig b/src/codegen/loongarch/abi.zig new file mode 100644 index 0000000000000000000000000000000000000000..09e42a7cb96731dbf0ee44b37ad74f0548a08c93 --- /dev/null +++ b/src/codegen/loongarch/abi.zig @@ -0,0 +1,133 @@ +const std = @import("std"); +const InternPool = @import("../../InternPool.zig"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); + +pub const Class = union(enum) { + ignored, + gar, + far, + member: Type, + member_pair: [2]Type, + memory_gar, + memory_gar_pair, + address, + + fn combineMember(container_class: Class, member_class: Class, member_ty: Type) Class { + const second_member_ty = switch (member_class) { + .ignored => return container_class, + .gar, .far => member_ty, + .member => |second_member_ty| second_member_ty, + .member_pair, .memory_gar, .memory_gar_pair, .address => return .address, + }; + return switch (container_class) { + .ignored => .{ .member = second_member_ty }, + .gar, .far, .memory_gar, .memory_gar_pair => unreachable, + .member => |first_member_ty| .{ .member_pair = .{ first_member_ty, second_member_ty } }, + .member_pair, .address => .address, + }; + } +}; + +pub fn classifyType(ty: Type, zcu: *Zcu) Class { + return Classifier.init(zcu).classifyType(ty); +} + +const Classifier = struct { + zcu: *Zcu, + target: *const std.Target, + grlen: u8, + frlen: u8, + + fn init(zcu: *Zcu) Classifier { + const target = zcu.getTarget(); + return .{ + .zcu = zcu, + .target = target, + .grlen = switch (target.cpu.arch) { + else => unreachable, + .loongarch32 => 32, + .loongarch64 => 64, + }, + .frlen = if (target.cpu.has(.loongarch, .d)) + 64 + else if (target.cpu.has(.loongarch, .f)) + 32 + else + 0, + }; + } + + fn classifyType(c: Classifier, ty: Type) Class { + switch (ty.zigTypeTag(c.zcu)) { + .type, + .comptime_float, + .comptime_int, + .undefined, + .null, + .error_union, + .error_set, + .@"fn", + .@"opaque", + .frame, + .@"anyframe", + .enum_literal, + .spirv, + => unreachable, + .void, .noreturn => return .ignored, + .bool => return .gar, + .int, .@"enum" => { + const bits = ty.intInfo(c.zcu).bits; + if (bits == 0) return .ignored; + if (bits <= c.grlen) return .gar; + if (bits <= 2 * c.grlen) return .memory_gar_pair; + return .address; + }, + .float => { + const bits = ty.floatBits(c.target); + if (bits <= c.frlen) return .far; + if (bits <= c.grlen) return .gar; + if (bits <= 2 * c.grlen) return .memory_gar_pair; + return .address; + }, + .pointer, .optional => return .gar, + .array => { + var class: Class = .ignored; + const elem_ty = ty.childType(c.zcu); + const elem_class = c.classifyType(elem_ty); + for (0..std.math.lossyCast(usize, ty.arrayLen(c.zcu))) |_| { + class = class.combineMember(elem_class, elem_ty); + if (class == .address) break; + } + if (class != .address) return class; + }, + .@"struct" => switch (ty.containerLayout(c.zcu)) { + .auto => unreachable, + .@"extern" => { + var class: Class = .ignored; + var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (c.zcu.typeToStruct(ty)) |loaded_struct| + loaded_struct.iterateRuntimeOrder(&c.zcu.intern_pool) + else + .{ .runtime_order = null, .fields_len = ty.structFieldCount(c.zcu), .next_index = 0 }; + while (field_it.next()) |field_index| { + const field_ty = ty.fieldType(field_index, c.zcu); + class = class.combineMember(c.classifyType(field_ty), field_ty); + if (class == .address) break; + } + if (class != .address) return class; + }, + .@"packed" => return c.classifyType(ty.backingIntType(c.zcu)), + }, + .@"union" => switch (ty.containerLayout(c.zcu)) { + .auto => unreachable, + .@"extern" => {}, + .@"packed" => return c.classifyType(ty.backingIntType(c.zcu)), + }, + .vector => {}, + } + const size = ty.abiSize(c.zcu); + if (size <= @divExact(c.grlen, 8)) return .memory_gar; + if (size <= @divExact(2 * c.grlen, 8)) return .memory_gar_pair; + return .address; + } +}; diff --git a/src/codegen/mips/abi.zig b/src/codegen/mips/abi.zig index f512f1e6db98031dd581bc9cb19ef7be42b7ae29..e7c07582030cc16d73f07b0d56d56f09f0607a0f 100644 --- a/src/codegen/mips/abi.zig +++ b/src/codegen/mips/abi.zig @@ -38,7 +38,14 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { return .byval; }, .bool => return .byval, - .float => return .byval, + .float => return switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => .byval, + 80, 128 => switch (max_direct_size) { + else => unreachable, + 64 => .memory, + }, + }, .int, .@"enum", .error_set => { return .byval; }, diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig index 4ee131d079c666a52516e480137782e44f45a553..aed925be2953ddfb56581b9bb5eef521e8b78507 100644 --- a/src/codegen/riscv64/CodeGen.zig +++ b/src/codegen/riscv64/CodeGen.zig @@ -5036,7 +5036,7 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { .register_pair, => { if (ret_ty.isVector(zcu)) { - const bit_size = ret_ty.totalVectorBits(zcu); + const bit_size = ret_ty.bitSize(zcu); // set the vtype to hold the entire vector's contents in a single element try func.setVl(.zero, 0, .{ @@ -6871,7 +6871,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! // size to the total size of the vector, and vmv.x.s will work then if (src_reg.class() == .vector) { try func.setVl(.zero, 0, .{ - .vsew = switch (ty.totalVectorBits(zcu)) { + .vsew = switch (ty.bitSize(zcu)) { 8 => .@"8", 16 => .@"16", 32 => .@"32", diff --git a/src/codegen/riscv64/abi.zig b/src/codegen/riscv64/abi.zig index 5c89a35f7bd4e718e8e032093856f6068b751c9b..154118c50c98572fea63fcc00986c7cc338b3ca6 100644 --- a/src/codegen/riscv64/abi.zig +++ b/src/codegen/riscv64/abi.zig @@ -56,12 +56,20 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { return .integer; }, .bool => return .integer, - .float => return .byval, .int, .@"enum", .error_set => { const bit_size = ty.bitSize(zcu); if (bit_size > max_byval_size) return .memory; return .byval; }, + .float => return switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64, 128 => .byval, + 80 => switch (max_byval_size) { + else => unreachable, + 64 => .memory, + 128 => .double_integer, + }, + }, .vector => { const bit_size = ty.bitSize(zcu); if (bit_size > max_byval_size) return .memory; @@ -190,7 +198,7 @@ pub fn classifySystem(ty: Type, zcu: *Zcu) [8]SystemClass { }, .vector => { // we pass vectors through integer registers if they are small enough to fit. - const vec_bits = ty.totalVectorBits(zcu); + const vec_bits = ty.bitSize(zcu); if (vec_bits <= 64) { result[0] = .integer; return result; diff --git a/src/codegen/s390x/abi.zig b/src/codegen/s390x/abi.zig new file mode 100644 index 0000000000000000000000000000000000000000..7b35245fdad37be5e062bbcc873c116a78a99152 --- /dev/null +++ b/src/codegen/s390x/abi.zig @@ -0,0 +1,92 @@ +const assert = std.debug.assert; +const std = @import("std"); +const InternPool = @import("../../InternPool.zig"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); + +pub const Context = enum { ret, arg }; + +pub const Class = enum { + none, + double_or_float, + vector, + simple, + simple_aggregate, + pointer, +}; + +pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class { + tag: switch (ty.zigTypeTag(zcu)) { + .type, + .comptime_float, + .comptime_int, + .undefined, + .null, + .error_union, + .error_set, + .@"fn", + .@"opaque", + .frame, + .@"anyframe", + .enum_literal, + .spirv, + => unreachable, + .void, .noreturn => return .none, + .bool => return .simple, + .int, .@"enum" => return switch (ty.intInfo(zcu).bits) { + 0 => .none, + 1...64 => .simple, + else => .pointer, + }, + .float => switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64 => return .double_or_float, + 80 => {}, + 128 => return .pointer, + }, + .pointer, .optional => return .simple, + .array => switch (ty.arrayLen(zcu)) { + 0 => return .none, + 1 => switch (context) { + .ret => {}, + .arg => return classifyType(ty.childType(zcu), context, zcu), + }, + else => {}, + }, + .@"struct", .@"union" => |tag| switch (ty.containerLayout(zcu)) { + .auto => unreachable, + .@"extern" => switch (context) { + .ret => {}, + .arg => { + var class: Class = .none; + for (0..switch (tag) { + else => unreachable, + .@"struct" => ty.structFieldCount(zcu), + .@"union" => ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu), + }) |field_index| { + switch (tag) { + else => unreachable, + .@"struct" => if (ty.structFieldIsComptime(field_index, zcu)) continue, + .@"union" => {}, + } + const field_class = classifyType(ty.fieldType(field_index, zcu), context, zcu); + if (field_class == .none) continue; + if (class != .none) break :tag; + class = field_class; + } + return class; + }, + }, + .@"packed" => return classifyType(ty.backingIntType(zcu), context, zcu), + }, + .vector => return if (ty.abiSize(zcu) <= 16) .vector else .pointer, + } + return switch (ty.abiSize(zcu)) { + 0 => .none, + 1, 2, 4, 8 => switch (context) { + .ret => .pointer, + .arg => .simple_aggregate, + }, + else => .pointer, + }; +} diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index e0e73040cab9dedecaaca4c4f843e647e87edcd5..2848a5f2573c75c73036aa2ff19f583403a9085f 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -24,12 +24,6 @@ const Alignment = InternPool.Alignment; const errUnionPayloadOffset = codegen.errUnionPayloadOffset; const errUnionErrorOffset = codegen.errUnionErrorOffset; -const target_util = @import("../../target.zig"); -const libcFloatPrefix = target_util.libcFloatPrefix; -const libcFloatSuffix = target_util.libcFloatSuffix; -const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev; -const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; - pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { return comptime &.initMany(&.{ .expand_bit_cast_safe, @@ -2515,15 +2509,15 @@ const IntType = struct { .anyerror, .adhoc_inferred_error_set => .{ .is_signed = false, .bits = zcu.errorSetBits() }, .isize => .{ .is_signed = true, .bits = cg.target.ptrBitWidth() }, .usize => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() }, - .c_char => .{ .is_signed = cg.target.cCharSignedness() == .signed, .bits = cg.target.cTypeBitSize(.char) }, - .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short) }, - .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short) }, - .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int) }, - .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int) }, - .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long) }, - .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long) }, - .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong) }, - .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong) }, + .c_char => .{ .is_signed = cg.target.cCharSignedness().? == .signed, .bits = cg.target.cTypeBitSize(.char).? }, + .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short).? }, + .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short).? }, + .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int).? }, + .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int).? }, + .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long).? }, + .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long).? }, + .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong).? }, + .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong).? }, .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable, .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable, }, @@ -4340,7 +4334,7 @@ fn floatRem(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fmodf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmod, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fmodx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fmodq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fmodf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4376,7 +4370,7 @@ fn floatMax(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fmaxf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmax, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fmaxx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fmaxq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fmaxf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4387,7 +4381,7 @@ fn floatMin(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fminf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmin, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fminx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fminq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fminf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4405,7 +4399,7 @@ fn floatSqrt(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__sqrtx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.sqrtq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.sqrtf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4415,7 +4409,7 @@ fn floatSin(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.sinf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.sin, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__sinx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.sinq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.sinf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4425,7 +4419,7 @@ fn floatCos(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.cosf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.cos, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__cosx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.cosq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.cosf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4435,7 +4429,7 @@ fn floatTan(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.tanf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.tan, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__tanx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.tanq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.tanf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4445,7 +4439,7 @@ fn floatExp(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.expf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.exp, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__expx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.expq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.expf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4455,7 +4449,7 @@ fn floatExp2(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.exp2f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.exp2, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__exp2x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.exp2q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.exp2f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4465,7 +4459,7 @@ fn floatLog(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.logf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__logx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.logq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.logf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4475,7 +4469,7 @@ fn floatLog2(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.log2f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log2, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__log2x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.log2q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.log2f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4485,7 +4479,7 @@ fn floatLog10(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.log10f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log10, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__log10x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.log10q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.log10f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4503,7 +4497,7 @@ fn floatFloor(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__floorx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.floorq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.floorf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4521,7 +4515,7 @@ fn floatCeil(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__ceilx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.ceilq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.ceilf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4539,7 +4533,7 @@ fn floatRound(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__roundx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.roundq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.roundf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4557,7 +4551,7 @@ fn floatTrunc(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__truncx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.truncq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.truncf128, &.{.f128_type}, Type.f128, &.{arg}), } } diff --git a/src/codegen/wasm/Mir.zig b/src/codegen/wasm/Mir.zig index 8e5f1c32f958d8ea2403ea2260a421da08e153c9..bbb41312990a836c336b6a3aa303ba2f0e363521 100644 --- a/src/codegen/wasm/Mir.zig +++ b/src/codegen/wasm/Mir.zig @@ -991,48 +991,48 @@ pub const Intrinsic = enum(u32) { __udivti3, __umodei5, __umodti3, - ceilq, + ceilf128, cos, cosf, - cosq, + cosf128, exp, exp2, exp2f, - exp2q, + exp2f128, expf, - expq, - fabsq, - floorq, + expf128, + fabsf128, + floorf128, fma, fmaf, - fmaq, + fmaf128, fmax, fmaxf, - fmaxq, + fmaxf128, fmin, fminf, - fminq, + fminf128, fmod, fmodf, - fmodq, + fmodf128, log, log10, log10f, - log10q, + log10f128, log2, log2f, - log2q, + log2f128, logf, - logq, - roundq, + logf128, + roundf128, sin, sinf, - sinq, - sqrtq, + sinf128, + sqrtf128, tan, tanf, - tanq, - truncq, + tanf128, + truncf128, memcpy, memmove, memset, diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig index 7a643e8dc7a755937f096f9826e5d770c2394b42..244b2c7719476ffa1542ce5863c11ac62c3c36de 100644 --- a/src/codegen/wasm/abi.zig +++ b/src/codegen/wasm/abi.zig @@ -25,7 +25,11 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { assert(ty.hasRuntimeBits(zcu)); switch (ty.zigTypeTag(zcu)) { .int, .@"enum", .error_set => return .{ .direct = ty }, - .float => return .{ .direct = ty }, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64, 128 => .{ .direct = ty }, + 80 => .indirect, + }, .bool => return .{ .direct = ty }, .vector => return .{ .direct = ty }, .array => return .indirect, diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index d499ef406fc67f0a7a4fe8c81390b6ad434a36a5..4958d17e304cb7cccc3e4b383bd46e1d09141c0a 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -34436,7 +34436,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34470,7 +34470,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34505,7 +34505,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34540,7 +34540,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34575,7 +34575,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34612,7 +34612,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34649,7 +34649,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34688,7 +34688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34727,7 +34727,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34766,7 +34766,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -35960,8 +35960,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -35998,8 +35998,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36037,8 +36037,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36076,8 +36076,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36115,8 +36115,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36156,8 +36156,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36197,8 +36197,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36240,8 +36240,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36283,8 +36283,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36326,8 +36326,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -37691,7 +37691,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37725,7 +37725,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37760,7 +37760,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37795,7 +37795,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37830,7 +37830,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37867,7 +37867,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37904,7 +37904,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37943,7 +37943,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37982,7 +37982,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -38021,7 +38021,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -39558,7 +39558,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39590,7 +39590,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39623,7 +39623,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39659,7 +39659,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39695,7 +39695,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39731,7 +39731,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -39767,7 +39767,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -39803,7 +39803,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -42803,7 +42803,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42849,7 +42849,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42895,7 +42895,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42942,7 +42942,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42984,7 +42984,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43029,7 +43029,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43074,7 +43074,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43120,7 +43120,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .reg = .rax } }, .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, @@ -43164,7 +43164,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43211,7 +43211,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43258,7 +43258,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43306,7 +43306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -47623,7 +47623,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47655,7 +47655,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47688,7 +47688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47724,7 +47724,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47760,7 +47760,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47796,7 +47796,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -47832,7 +47832,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -47868,7 +47868,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -51926,7 +51926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -51958,7 +51958,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -51991,7 +51991,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52027,7 +52027,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52063,7 +52063,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52099,7 +52099,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -52135,7 +52135,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -52171,7 +52171,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76457,7 +76457,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76484,7 +76484,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76512,7 +76512,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76543,7 +76543,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76574,7 +76574,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76605,7 +76605,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76636,7 +76636,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76667,7 +76667,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77306,7 +77306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77333,7 +77333,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77361,7 +77361,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77392,7 +77392,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77423,7 +77423,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77454,7 +77454,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77485,7 +77485,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77516,7 +77516,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -80155,9 +80155,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80187,9 +80187,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80220,9 +80220,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80256,9 +80256,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80292,9 +80292,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80328,9 +80328,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -80364,9 +80364,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -80400,9 +80400,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -125531,7 +125531,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .call, .tmp1d, ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse, null, null, null }, .src_constraints = .{ .{ .unsigned_int = .xword }, .any, .any }, .dst_constraints = .{ .{ .float = .xword }, .any }, @@ -125557,34 +125556,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .each = .{ .once = &.{ .{ ._, ._, .call, .tmp0d, ._, ._, ._ }, } }, - }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse, null, null, null }, - .src_constraints = .{ .{ .unsigned_int = .xword }, .any, .any }, - .dst_constraints = .{ .{ .float = .xword }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } }, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ }, - .{ ._, ._, .call, .tmp1d, ._, ._, ._ }, - } }, }, .{ .required_features = .{ .@"64bit", .sse, null, null }, .src_constraints = .{ .{ .remainder_signed_int = .{ .of = .dword, .is = .dword } }, .any, .any }, @@ -126791,7 +126762,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .avx, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126824,39 +126794,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .win64, - .required_features = .{ .avx, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, .v_dqa, .mov, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, - }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse2, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126889,39 +126826,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse2, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, ._dqa, .mov, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, - }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126953,38 +126857,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, - }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, ._ps, .mova, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, }, .{ .required_features = .{ .@"64bit", .avx, null, null }, .src_constraints = .{ .{ .scalar_remainder_signed_int = .{ .of = .dword, .is = .dword } }, .any, .any }, @@ -142552,7 +142424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142584,7 +142456,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142616,7 +142488,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142649,7 +142521,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -142683,7 +142555,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -142717,7 +142589,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152785,7 +152657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152817,7 +152689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152849,7 +152721,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152882,7 +152754,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152916,7 +152788,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152950,7 +152822,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163019,7 +162891,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163051,7 +162923,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163083,7 +162955,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163116,7 +162988,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163150,7 +163022,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163184,7 +163056,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164816,7 +164688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164848,7 +164720,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164880,7 +164752,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164913,7 +164785,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164947,7 +164819,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164981,7 +164853,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -172785,7 +172657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172818,7 +172690,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172852,7 +172724,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172889,7 +172761,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172926,7 +172798,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172963,7 +172835,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -173000,7 +172872,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -173037,7 +172909,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -182636,15 +182508,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int { .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }, .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() }, .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, - .c_char => .{ .signedness = cg.target.cCharSignedness(), .bits = cg.target.cTypeBitSize(.char) }, - .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short) }, - .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short) }, - .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int) }, - .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int) }, - .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long) }, - .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long) }, - .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong) }, - .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong) }, + .c_char => .{ .signedness = cg.target.cCharSignedness().?, .bits = cg.target.cTypeBitSize(.char).? }, + .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short).? }, + .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short).? }, + .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int).? }, + .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int).? }, + .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long).? }, + .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long).? }, + .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong).? }, + .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong).? }, .f16, .f32, .f64, .f80, .f128, .c_longdouble => null, .anyopaque, .void, diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 3e7a9a548d54baee16d64a54de9a42c4650f7ea5..1e01ff508af3a29367f9cfbb1ea74d412147d70a 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -133,7 +133,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx: .float => switch (ty.floatBits(target)) { 16, 32, 64 => .sse, 80 => .memory, - 128 => if (ctx == .arg) .memory else .sse, + 128 => .win_i128, else => unreachable, }, .vector => { @@ -238,16 +238,18 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont }; const unaligned_size = elem_ty.abiSize(zcu) * len; if (unaligned_size <= 4) return Class.one_integer; - if (ctx == .arg and unaligned_size == 8 * 1 * 1 and len == 1 and - elem_ty.isRuntimeFloat()) return Class.stack; // what + if (unaligned_size == 8 * 1 * 1 and len == 1) { + if (ctx == .arg and elem_ty.isRuntimeFloat()) return Class.stack; // what? + if (ctx != .other and !elem_ty.isRuntimeFloat() and target.os.tag == .freebsd) return Class.one_integer; // who? + } if (unaligned_size <= 8 * 1) return .{ .sse, .none, .none, .none, .none, .none, .none, .none }; if (unaligned_size <= 8 * 2) return .{ .sse, .sseup, .none, .none, .none, .none, .none, .none }; if (!target.cpu.has(.x86, .avx)) { if (ctx == .ret) switch (unaligned_size) { else => {}, 8 * 3 => if (len == 3) return if (elem_ty.isRuntimeFloat()) .{ - .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how - } else Class.len_integers, // why + .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how? + } else Class.len_integers, // why? 8 * 2 * 2, 8 * 2 * 4 => return .{ .sse_per_xword, .none, .none, .none, .none, .none, .none, .none }, }; return Class.stack; @@ -356,11 +358,10 @@ fn classifySystemVStruct( while (field_it.next()) |field_index| { const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); const field_align = loaded_struct.field_aligns.getOrNone(ip, field_index); - byte_offset = std.mem.alignForward( - u64, - byte_offset, - field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?, - ); + byte_offset = switch (field_align) { + .none => field_ty.abiAlignment(zcu), + else => field_align, + }.forward(byte_offset); if (zcu.typeToStruct(field_ty)) |field_loaded_struct| { switch (field_loaded_struct.layout) { .auto => unreachable, @@ -379,6 +380,9 @@ fn classifySystemVStruct( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + byte_offset = classifySystemVArray(result, byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -386,11 +390,7 @@ fn classifySystemVStruct( byte_offset += field_ty.abiSize(zcu); } const final_byte_offset = starting_byte_offset + loaded_struct.size; - std.debug.assert(final_byte_offset == std.mem.alignForward( - u64, - byte_offset, - loaded_struct.alignment.toByteUnits().?, - )); + std.debug.assert(final_byte_offset == loaded_struct.alignment.forward(byte_offset)); return final_byte_offset; } @@ -422,6 +422,9 @@ fn classifySystemVUnion( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + _ = classifySystemVArray(result, starting_byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(starting_byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -430,6 +433,26 @@ fn classifySystemVUnion( return starting_byte_offset + loaded_union.size; } +fn classifySystemVArray( + result: *[8]Class, + starting_byte_offset: u64, + array_ty: Type, + zcu: *Zcu, + target: *const std.Target, +) u64 { + const field_classes = std.mem.sliceTo(&classifySystemV(array_ty.childType(zcu), zcu, target, .other), .none); + var byte_offset = starting_byte_offset; + const elem_size = array_ty.childType(zcu).abiSize(zcu); + for (0..@intCast(array_ty.arrayLen(zcu))) |_| { + for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| + result_class.* = result_class.combineSystemV(field_class); + byte_offset += elem_size; + } + const final_byte_offset = starting_byte_offset + array_ty.abiSize(zcu); + assert(final_byte_offset == byte_offset); + return final_byte_offset; +} + pub const zigcc = struct { pub const stack_align: ?InternPool.Alignment = null; pub const return_in_regs = true; diff --git a/src/libs/mingw/Preprocessor.zig b/src/libs/mingw/Preprocessor.zig index dcf8e01d043dbc6790aeff839718fd65b5e621cd..9098b6013a4179ba15de85707d70d290f09bd116 100644 --- a/src/libs/mingw/Preprocessor.zig +++ b/src/libs/mingw/Preprocessor.zig @@ -91,9 +91,9 @@ fn addTokenAssumeCapacity(pp: *Preprocessor, tok: Token) void { fn defineBuiltins(pp: *Preprocessor) !void { var buf: [5]u8 = undefined; - var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.longdouble)}) catch unreachable; + var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.longdouble).?}) catch unreachable; try pp.defineBuiltinValue("__SIZEOF_LONG_DOUBLE__", val, .pp_num); - val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.double)}) catch unreachable; + val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.double).?}) catch unreachable; try pp.defineBuiltinValue("__SIZEOF_DOUBLE__", val, .pp_num); if (pp.target.abi.isGnu()) { diff --git a/src/link.zig b/src/link.zig index 84cbcbdcb78ea45a0e9e93242686f7f8f0f01748..15d9fcb513a8b329d6ebfbc6cf66d92b02352bc8 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1238,7 +1238,7 @@ pub const File = struct { } switch (base.tag) { - inline .elf2, .coff2, .wasm => |tag| { + inline .elf2, .coff2, .wasm, .c => |tag| { dev.check(tag.devFeature()); try @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); }, @@ -2127,7 +2127,7 @@ pub fn resolveInputs( continue; }, } - @compileError("unreachable"); + comptime unreachable; } if (failed_libs.items.len > 0) { diff --git a/src/link/C.zig b/src/link/C.zig index a6830126fb2f048af065093adf6e99e2778e0c88..cf82ed146fa853cc449074721eb294834cde6d1b 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -43,6 +43,8 @@ type_dependencies: std.ArrayList(link.ConstPool.Index), /// one array. align_dependency_masks: std.ArrayList(u64), +/// Emitted at the top of the file. This can be cached since it only depends on the target. +header: String, /// All NAVs, regardless of whether they are functions or simple constants, are put in this map. navs: std.array_hash_map.Auto(InternPool.Nav.Index, RenderedDecl), /// All UAVs which may be referenced are in this map. The UAV alignment is not included in the @@ -404,9 +406,8 @@ pub fn createEmpty( emit: Path, options: link.File.OpenOptions, ) !*C { + assert(comp.root_mod.resolved_target.result.ofmt == .c); const io = comp.io; - const target = &comp.root_mod.resolved_target.result; - assert(target.ofmt == .c); const optimize_mode = comp.root_mod.optimize_mode; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -422,9 +423,8 @@ pub fn createEmpty( }); errdefer file.close(io); - const c_file = try arena.create(C); - - c_file.* = .{ + const c = try arena.create(C); + c.* = .{ .base = .{ .tag = .c, .comp = comp, @@ -439,6 +439,7 @@ pub fn createEmpty( .string_bytes = .empty, .type_dependencies = .empty, .align_dependency_masks = .empty, + .header = .empty, .navs = .empty, .uavs = .empty, .type_pool = .empty, @@ -447,8 +448,7 @@ pub fn createEmpty( .exported_navs = .empty, .exported_uavs = .empty, }; - - return c_file; + return c; } pub fn deinit(c: *C) void { @@ -469,6 +469,21 @@ pub fn deinit(c: *C) void { c.exported_uavs.deinit(gpa); } +pub fn prelink(c: *C, prog_node: std.Progress.Node) !void { + const comp = c.base.comp; + + const sub_prog_node = prog_node.start("Generate Header", 0); + defer sub_prog_node.end(); + + var header_aw: std.Io.Writer.Allocating = .init(comp.gpa); + defer header_aw.deinit(); + codegen.genHeader(comp.zcu.?, &header_aw.writer) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + else => |e| return e, + }; + c.header = try c.addString(&.{header_aw.written()}); +} + pub fn updateContainerType( c: *C, pt: Zcu.PerThread, @@ -727,7 +742,6 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog const io = comp.io; const zcu = c.base.comp.zcu.?; const ip = &zcu.intern_pool; - const target = zcu.getTarget(); const active = zcu.activate(tid); defer active.deactivate(); const pt = active.pt; @@ -943,7 +957,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // We have discovered the full set of NAVs, UAVs, and types we need to emit, and will now begin // to build the output buffer. Our strategy is to emit the C source in this order: // - // * ABI defines and `#include "zig.h"` + // * Header // * Big-int type definitions // * Other CType definitions (traversing the dependency graph to sort topologically) // * Global assembly @@ -968,7 +982,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // We know exactly what we'll be emitting, so can reserve capacity for all of our buffers! - try f.all_buffers.ensureUnusedCapacity(gpa, 3 + // ABI defines and `#include "zig.h"` + try f.all_buffers.ensureUnusedCapacity(gpa, 1 + // Header 1 + // Big-int type definitions need_types.count() + // `RenderedType.fwd_decl` (worst-case) need_types.count() + // `RenderedType.definition` @@ -984,20 +998,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog need_uavs.count() * 3 + // UAV definitions ("static ", "zig_align(4)", "") need_navs.count() * 2); // NAV definitions ("static ", "") - // ABI defines and `#include "zig.h"` - switch (target.abi) { - .msvc, .itanium => f.appendBufAssumeCapacity("#define ZIG_TARGET_ABI_MSVC\n"), - else => {}, - } - f.appendBufAssumeCapacity(try std.fmt.allocPrint( - arena, - "#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", - .{target.cMaxIntAlignment()}, - )); - f.appendBufAssumeCapacity( - \\#include "zig.h" - \\ - ); + f.appendBufAssumeCapacity(c.header.get(c)); // Big-int type definitions var bigint_aw: std.Io.Writer.Allocating = .init(gpa); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 1b2aa830d23ee24903085a36db49ce1a42c91c72..52d0fc57a1d5238ac2fd837d10878083a94510c7 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4151,8 +4151,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co .x86_64_regcall_v3_sysv => .LLVM_X86RegCall, .x86_64_regcall_v4_win => .LLVM_X86RegCall, .x86_64_vectorcall => .LLVM_vectorcall, - .x86_sysv => .normal, - .x86_win => .normal, + .x86_sysv, .x86_win, .x86_mingw => .normal, .x86_stdcall => .BORLAND_stdcall, .x86_fastcall => .BORLAND_msfastcall, .x86_thiscall => .BORLAND_thiscall, diff --git a/src/main.zig b/src/main.zig index 94011c81f9215df1da00328f221c41e42b9bc214..a7b8ddb6d08cac1dfd2b882f4dda65ec03c181d1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3835,11 +3835,17 @@ fn buildOutputType( var prev_has_cflags = false; var prev_has_rcflags = false; - if (dirs.zig_lib.path) |zig_lib_path| { - try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); - prev_has_cflags = true; + { + if (dirs.zig_lib.path) |zig_lib_path| { + try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); + prev_has_cflags = true; + } + const emit_ext: Compilation.FileExt = .c; + const need_lang = if (comp.emit_bin) |comp_emit_bin| Compilation.classifyFileExt(comp_emit_bin) != emit_ext else true; + if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", emit_ext.toLang() }); + try test_exec_args.append(arena, null); + if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); } - try test_exec_args.append(arena, null); for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| { for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| { const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len; diff --git a/src/target.zig b/src/target.zig index 0ed4053701fd696db7540b42dbf5aaf890e47921..b4dc16b3185bb4e60ec99d93e2a39595f815eeed 100644 --- a/src/target.zig +++ b/src/target.zig @@ -876,18 +876,18 @@ pub fn libcFloatSuffix(float_bits: u16) []const u8 { 32 => "f", 64 => "", 80 => "x", // Non-standard - 128 => "q", // Non-standard (mimics convention in GCC libquadmath) + 128 => "f128", else => unreachable, }; } -pub fn compilerRtFloatAbbrev(float_bits: u16) []const u8 { +pub fn compilerRtFloatAbbrev(target: *const std.Target, float_bits: u16) []const u8 { return switch (float_bits) { 16 => "h", 32 => "s", 64 => "d", 80 => "x", - 128 => "t", + 128 => if (target.cpu.arch.isPowerPC()) "k" else "t", else => unreachable, }; } diff --git a/stage1/zig.h b/stage1/zig.h index fbc924ca334e99eb12d2f37e3ebffa970ced7b9d..30e6f3f96a97f47b6648db1d1587bc75c88b6c3f 100644 --- a/stage1/zig.h +++ b/stage1/zig.h @@ -166,6 +166,12 @@ #endif #define zig_expand_has_builtin(b) zig_has_builtin(b) +#if defined(__has_feature) +#define zig_has_feature(feature) __has_feature(feature) +#else +#define zig_has_feature(feature) 0 +#endif + #if defined(__has_attribute) #define zig_has_attribute(attribute) __has_attribute(attribute) #else @@ -175,9 +181,9 @@ #if __STDC_VERSION__ >= 201112L #define zig_static_assert(cond, msg) _Static_assert(cond, msg) #elif zig_has_attribute(unused) -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused)) +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] __attribute__((unused)) #else -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] #endif #if __STDC_VERSION__ >= 202311L @@ -193,10 +199,8 @@ #endif #if defined(zig_msvc) -#define zig_const_arr #define zig_callconv(c) __##c #else -#define zig_const_arr static const #define zig_callconv(c) __attribute__((c)) #endif @@ -267,12 +271,20 @@ #if __STDC_VERSION__ >= 202311L #define zig_align(alignment) alignas(alignment) -#elif __STDC_VERSION__ >= 201112L +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignas) #define zig_align(alignment) _Alignas(alignment) #else #define zig_align(alignment) zig_under_align(alignment) #endif +#if __STDC_VERSION__ >= 202311L +#define zig_alignOf(Type) alignof(Type) +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignof) +#define zig_alignOf(Type) _Alignof(Type) +#else +#define zig_alignOf(Type) (sizeof(struct { char c; Type t; }) - sizeof(Type)) +#endif + #if zig_has_attribute(aligned) || defined(zig_tinyc) #define zig_align_fn(alignment) __attribute__((aligned(alignment))) #elif defined(zig_msvc) @@ -350,11 +362,9 @@ #define zig_export(symbol, name) __attribute__((alias(symbol))) #else #define zig_export(symbol, name) ; \ - __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) + __asm("\t.globl\t" zig_mangle_c(name) "\n" zig_mangle_c(name) " = " zig_mangle_c(symbol)) #endif -#define zig_mangled_tentative zig_mangled -#define zig_mangled_final zig_mangled #if defined(zig_msvc) #define zig_mangled(mangled, unmangled) ; \ zig_export(#mangled, unmangled) @@ -364,7 +374,7 @@ #else /* zig_msvc */ #define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled)) #define zig_mangled_export(mangled, unmangled, symbol) \ - zig_mangled_final(mangled, unmangled) \ + zig_mangled(mangled, unmangled) \ zig_export(symbol, unmangled) #endif /* zig_msvc */ @@ -550,6 +560,9 @@ #define zig_noreturn #endif +#define zig_has_always 1 +#define zig_has_never 0 + #define zig_compiler_rt_abbrev_uint32_t si #define zig_compiler_rt_abbrev_int32_t si #define zig_compiler_rt_abbrev_uint64_t di @@ -560,7 +573,11 @@ #define zig_compiler_rt_abbrev_zig_f32 sf #define zig_compiler_rt_abbrev_zig_f64 df #define zig_compiler_rt_abbrev_zig_f80 xf +#ifdef zig_powerpc +#define zig_compiler_rt_abbrev_zig_f128 kf +#else #define zig_compiler_rt_abbrev_zig_f128 tf +#endif zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t); zig_extern void *memset (void *, int, size_t); @@ -645,16 +662,6 @@ typedef signed long long int16_t; #define INT16_MAX ( INT16_C(0x7FFF)) #define UINT16_MAX ( INT16_C(0xFFFF)) -#if defined(zig_ez80) -typedef unsigned int uint24_t; -typedef signed int int24_t; -#define INT24_C(c) c -#define UINT24_C(c) c##U -#endif -#define INT24_MIN (~INT24_C(0x7FFF)) -#define INT24_MAX ( INT24_C(0x7FFF)) -#define UINT24_MAX ( INT24_C(0xFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF typedef unsigned char uint32_t; typedef signed char int32_t; @@ -685,17 +692,6 @@ typedef signed long long int32_t; #define INT32_MAX ( INT32_C(0x7FFFFFFF)) #define UINT32_MAX ( INT32_C(0xFFFFFFFF)) -#if defined(zig_ez80) -typedef unsigned __int48 uint48_t; -typedef signed __int48 int48_t; -#define INT48_C(c) c -/* no suffix */ -#define UINT48_C(c) ((uint48_t)(c)) -#endif -#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) -#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) -#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF typedef unsigned char uint64_t; typedef signed char int64_t; @@ -726,6 +722,27 @@ typedef signed long long int64_t; #define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF)) #define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF)) +#if defined(zig_ez80) + +typedef unsigned int uint24_t; +typedef signed int int24_t; +#define INT24_C(c) c +#define UINT24_C(c) c##U +#define INT24_MIN (~INT24_C(0x7FFF)) +#define INT24_MAX ( INT24_C(0x7FFF)) +#define UINT24_MAX ( INT24_C(0xFFFF)) + +typedef unsigned __int48 uint48_t; +typedef signed __int48 int48_t; +#define INT48_C(c) c +/* no suffix */ +#define UINT48_C(c) ((uint48_t)(c)) +#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) +#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) +#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) + +#endif + typedef size_t uintptr_t; typedef ptrdiff_t intptr_t; @@ -739,23 +756,145 @@ typedef ptrdiff_t intptr_t; #define zig_maxInt_i16 INT16_MAX #define zig_minInt_u16 UINT16_C(0) #define zig_maxInt_u16 UINT16_MAX -#define zig_minInt_i24 INT24_MIN -#define zig_maxInt_i24 INT24_MAX -#define zig_minInt_u24 UINT24_C(0) -#define zig_maxInt_u24 UINT24_MAX #define zig_minInt_i32 INT32_MIN #define zig_maxInt_i32 INT32_MAX #define zig_minInt_u32 UINT32_C(0) #define zig_maxInt_u32 UINT32_MAX -#define zig_minInt_i48 INT48_MIN -#define zig_maxInt_i48 INT48_MAX -#define zig_minInt_u48 UINT48_C(0) -#define zig_maxInt_u48 UINT48_MAX #define zig_minInt_i64 INT64_MIN #define zig_maxInt_i64 INT64_MAX #define zig_minInt_u64 UINT64_C(0) #define zig_maxInt_u64 UINT64_MAX +// zig_promoted_T implements C integral promotions except with signedness preserved, which +// allows wrapping operations to avoid the ub that would be caused by the normal promotion. + +#if INT8_MAX <= INT_MAX +typedef unsigned int zig_promoted_i8; +#elif INT8_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i8; +#elif INT8_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i8; +#else +typedef int8_t zig_promoted_i8; +#endif +#if UINT8_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u8; +#elif UINT8_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u8; +#elif UINT8_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u8; +#else +typedef uint8_t zig_promoted_u8; +#endif + +#if INT16_MAX <= INT_MAX +typedef unsigned int zig_promoted_i16; +#elif INT16_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i16; +#elif INT16_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i16; +#else +typedef int16_t zig_promoted_i16; +#endif +#if UINT16_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u16; +#elif UINT16_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u16; +#elif UINT16_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u16; +#else +typedef uint16_t zig_promoted_u16; +#endif + +#if INT32_MAX <= INT_MAX +typedef unsigned int zig_promoted_i32; +#elif INT32_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i32; +#elif INT32_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i32; +#else +typedef int32_t zig_promoted_i32; +#endif +#if UINT32_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u32; +#elif UINT32_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u32; +#elif UINT32_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u32; +#else +typedef uint32_t zig_promoted_u32; +#endif + +#if INT64_MAX <= INT_MAX +typedef unsigned int zig_promoted_i64; +#elif INT64_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i64; +#elif INT64_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i64; +#else +typedef int64_t zig_promoted_i64; +#endif +#if UINT64_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u64; +#elif UINT64_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u64; +#elif UINT64_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u64; +#else +typedef uint64_t zig_promoted_u64; +#endif + +#ifdef zig_ez80 + +#define zig_minInt_i24 INT24_MIN +#define zig_maxInt_i24 INT24_MAX +#define zig_minInt_u24 UINT24_C(0) +#define zig_maxInt_u24 UINT24_MAX +#define zig_minInt_i48 INT48_MIN +#define zig_maxInt_i48 INT48_MAX +#define zig_minInt_u48 UINT48_C(0) +#define zig_maxInt_u48 UINT48_MAX + +#if INT24_MAX <= INT_MAX +typedef unsigned int zig_promoted_i24; +#elif INT24_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i24; +#elif INT24_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i24; +#else +typedef int24_t zig_promoted_i24; +#endif +#if UINT24_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u24; +#elif UINT24_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u24; +#elif UINT24_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u24; +#else +typedef uint24_t zig_promoted_u24; +#endif + +#if INT48_MAX <= INT_MAX +typedef unsigned int zig_promoted_i48; +#elif INT48_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i48; +#elif INT48_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i48; +#else +typedef int48_t zig_promoted_i48; +#endif +#if UINT48_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u48; +#elif UINT48_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u48; +#elif UINT48_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u48; +#else +typedef uint48_t zig_promoted_u48; +#endif + +#endif + #define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits)) #define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits) #define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits) @@ -770,7 +909,33 @@ typedef ptrdiff_t intptr_t; zig_operator(Type, Type, operation, operator) #define zig_shift_operator(Type, operation, operator) \ zig_operator(Type, uint8_t, operation, operator) -#define zig_int_helpers(w, PromotedUnsigned) \ + +#define zig_int_casts_common(bw, sw) \ + static inline uint##bw##_t zig_u##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##bw##_t zig_u##bw##_intCast_i##sw(int##sw##_t arg) { \ + return (uint##bw##_t)arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_i##sw(int##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_truncate_u##bw(uint##bw##_t arg, uint8_t bits) { \ + return (uint##sw##_t)arg & zig_maxInt_u(sw, bits); \ + } \ +\ + static inline int##sw##_t zig_i##sw##_truncate_i##bw(int##bw##_t arg, uint8_t bits) { \ + return ((uint##sw##_t)arg & UINT##sw##_C(1) << (bits - UINT8_C(1))) != UINT##sw##_C(0) \ + ? (int##sw##_t)arg | zig_minInt_i(sw, bits) : (int##sw##_t)arg & zig_maxInt_i(sw, bits); \ + } +#define zig_int_operators(w) \ zig_basic_operator(uint##w##_t, and_u##w, &) \ zig_basic_operator( int##w##_t, and_i##w, &) \ zig_basic_operator(uint##w##_t, or_u##w, |) \ @@ -786,44 +951,48 @@ typedef ptrdiff_t intptr_t; return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ } \ \ - static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \ - return val ^ zig_maxInt_u(w, bits); \ + static inline uint##w##_t zig_not_u##w(uint##w##_t arg, uint8_t bits) { \ + return arg ^ zig_maxInt_u(w, bits); \ } \ \ - static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \ + static inline int##w##_t zig_not_i##w(int##w##_t arg, uint8_t bits) { \ (void)bits; \ - return ~val; \ + return ~arg; \ } \ \ - static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \ - return val & zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \ - return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \ - ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_abs_i##w(int##w##_t val) { \ - return (val < 0) ? -(uint##w##_t)val : (uint##w##_t)val; \ - } \ -\ - zig_basic_operator(uint##w##_t, div_floor_u##w, /) \ + zig_basic_operator(uint##w##_t, divFloor_u##w, /) \ \ - static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divFloor_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ } \ \ - static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + static inline uint##w##_t zig_divCeil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ } \ \ - static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divCeil_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ } \ \ zig_basic_operator(uint##w##_t, mod_u##w, %) \ + zig_int_casts_common(w, w) \ +\ + static inline uint##w##_t zig_u##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w(arg, bits); \ + } \ +\ + static inline uint##w##_t zig_u##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_u##w##_bitCast_u##w((uint##w##_t)arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w(arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_i##w##_bitCast_i##w((int##w##_t)arg, bits); \ + } \ \ static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \ int##w##_t rem = lhs % rhs; \ @@ -831,100 +1000,102 @@ typedef ptrdiff_t intptr_t; } \ \ static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ + return zig_u##w##_truncate_u##w(zig_shl_u##w(lhs, rhs), bits); \ } \ \ static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_shl_u##w(zig_u##w##_bitCast_i##w(lhs, bits), rhs), bits); \ } \ \ static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs + rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs + rhs, bits); \ } \ \ static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_addw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs - rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs - rhs, bits); \ } \ \ static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_subw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs * rhs, bits); \ } \ \ static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_mulw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ + } \ +\ + static inline uint##w##_t zig_abs_i##w(int##w##_t arg) { \ + int##w##_t tmp = zig_shr_i##w(arg, UINT8_C(w) - UINT8_C(1)); \ + return zig_u##w##_bitCast_i##w(zig_subw_i##w(zig_xor_i##w(arg, tmp), tmp, UINT8_C(w)), UINT8_C(w)); \ + } \ +\ + static inline uint##w##_t zig_min_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_min_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline uint##w##_t zig_max_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_max_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ } -#if UINT8_MAX <= UINT_MAX -zig_int_helpers(8, unsigned int) -#elif UINT8_MAX <= ULONG_MAX -zig_int_helpers(8, unsigned long) -#elif UINT8_MAX <= ULLONG_MAX -zig_int_helpers(8, unsigned long long) -#else -zig_int_helpers(8, uint8_t) +zig_int_operators(8) +zig_int_operators(16) +zig_int_operators(32) +zig_int_operators(64) +#ifdef zig_ez80 +zig_int_operators(24) +zig_int_operators(48) #endif -#if UINT16_MAX <= UINT_MAX -zig_int_helpers(16, unsigned int) -#elif UINT16_MAX <= ULONG_MAX -zig_int_helpers(16, unsigned long) -#elif UINT16_MAX <= ULLONG_MAX -zig_int_helpers(16, unsigned long long) -#else -zig_int_helpers(16, uint16_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(24, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(24, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(24, unsigned long long) -#else -zig_int_helpers(24, uint24_t) -#endif -#endif -#if UINT32_MAX <= UINT_MAX -zig_int_helpers(32, unsigned int) -#elif UINT32_MAX <= ULONG_MAX -zig_int_helpers(32, unsigned long) -#elif UINT32_MAX <= ULLONG_MAX -zig_int_helpers(32, unsigned long long) -#else -zig_int_helpers(32, uint32_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(48, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(48, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(48, unsigned long long) -#else -zig_int_helpers(48, uint48_t) -#endif -#endif -#if UINT64_MAX <= UINT_MAX -zig_int_helpers(64, unsigned int) -#elif UINT64_MAX <= ULONG_MAX -zig_int_helpers(64, unsigned long) -#elif UINT64_MAX <= ULLONG_MAX -zig_int_helpers(64, unsigned long long) -#else -zig_int_helpers(64, uint64_t) + +#define zig_int_casts(bw, sw) \ + static inline uint##sw##_t zig_u##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + zig_int_casts_common(bw, sw) +zig_int_casts(16, 8) +zig_int_casts(32, 8) +zig_int_casts(64, 8) +zig_int_casts(32, 16) +zig_int_casts(64, 16) +zig_int_casts(64, 32) +#ifdef zig_ez80 +zig_int_casts(32, 24) +zig_int_casts(48, 24) +zig_int_casts(64, 24) +zig_int_casts(64, 48) #endif static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_addw_u32(lhs, rhs, bits); @@ -936,19 +1107,19 @@ static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs + (uint32_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i32(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_addw_u64(lhs, rhs, bits); @@ -960,24 +1131,24 @@ static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs + (uint64_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i64(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -986,12 +1157,12 @@ static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(add_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1000,12 +1171,12 @@ static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1014,27 +1185,28 @@ static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_addo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1043,28 +1215,26 @@ static inline bool zig_addo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_addo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_addo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1073,22 +1243,23 @@ static inline bool zig_addo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_addo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_subw_u32(lhs, rhs, bits); @@ -1100,20 +1271,19 @@ static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs - (uint32_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i32(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } - static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_subw_u64(lhs, rhs, bits); @@ -1125,24 +1295,24 @@ static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs - (uint64_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i64(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1151,12 +1321,12 @@ static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1165,12 +1335,12 @@ static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1179,27 +1349,28 @@ static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_subo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1208,28 +1379,26 @@ static inline bool zig_subo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_subo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_subo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1238,22 +1407,23 @@ static inline bool zig_subo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_subo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_mulw_u32(lhs, rhs, bits); @@ -1261,8 +1431,8 @@ static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8 #endif } -zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { + zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1271,7 +1441,7 @@ static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t int32_t full_res = __mulosi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i32(full_res, bits); + *res = zig_i32_truncate_i32(full_res, bits); return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } @@ -1279,7 +1449,7 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_mulw_u64(lhs, rhs, bits); @@ -1287,8 +1457,8 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #endif } -zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { + zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1297,7 +1467,7 @@ static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t int64_t full_res = __mulodi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i64(full_res, bits); + *res = zig_i64_truncate_i64(full_res, bits); return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } @@ -1305,12 +1475,12 @@ static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t b #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1319,12 +1489,12 @@ static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1333,12 +1503,12 @@ static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1347,27 +1517,28 @@ static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_mulo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1376,28 +1547,26 @@ static inline bool zig_mulo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_mulo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_mulo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1406,18 +1575,32 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_mulo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif -#define zig_int_builtins(w) \ +#define zig_shls_builtins(lw, rw) \ + static inline uint##lw##_t zig_shls_u##lw##_u##rw(uint##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + uint##lw##_t res; \ + if (rhs < bits && !zig_shlo_u##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? zig_minInt_u(lw, bits) : zig_maxInt_u(lw, bits); \ + } \ +\ + static inline int##lw##_t zig_shls_i##lw##_u##rw(int##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + int##lw##_t res; \ + if (rhs < bits && !zig_shlo_i##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? INT##lw##_C(0) : \ + lhs < INT##lw##_C(0) ? zig_minInt_i(lw, bits) : zig_maxInt_i(lw, bits); \ + } +#define zig_int_sat_builtins(w) \ static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ return lhs > zig_maxInt_u(w, bits) >> rhs; \ @@ -1429,18 +1612,10 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \ } \ \ - static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - if (rhs < bits && !zig_shlo_u##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_shls_i##w(int##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (rhs < bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ - lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ + zig_shls_builtins(w, 8) \ + zig_shls_builtins(w, 16) \ + zig_shls_builtins(w, 32) \ + zig_shls_builtins(w, 64) \ \ static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ uint##w##_t res; \ @@ -1474,332 +1649,321 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ } -zig_int_builtins(8) -zig_int_builtins(16) +zig_int_sat_builtins(8) +zig_int_sat_builtins(16) +zig_int_sat_builtins(32) +zig_int_sat_builtins(64) #if defined(zig_ez80) -zig_int_builtins(24) +zig_int_sat_builtins(24) +zig_int_sat_builtins(48) #endif -zig_int_builtins(32) -#if defined(zig_ez80) -zig_int_builtins(48) -#endif -zig_int_builtins(64) -#define zig_builtin8(name, val) __builtin_##name(val) +#define zig_builtin8(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin8; -#define zig_builtin16(name, val) __builtin_##name(val) +#define zig_builtin16(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin16; -#if defined(zig_ez80) -#define zig_builtin24(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin24; -#endif - #if INT_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name(val) +#define zig_builtin32(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin32; #elif LONG_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name##l(val) +#define zig_builtin32(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin32; #endif -#if defined(zig_ez80) -#define zig_builtin48(name, val) __builtin_##name(val) -typedef unsigned long long zig_Builtin48; -#endif - #if INT_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name(val) +#define zig_builtin64(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin64; #elif LONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##l(val) +#define zig_builtin64(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin64; #elif LLONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##ll(val) +#define zig_builtin64(name, arg) __builtin_##name##ll(arg) typedef unsigned long long zig_Builtin64; #endif -static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { - return zig_wrap_u8(val >> (8 - bits), bits); +#if defined(zig_ez80) +#define zig_builtin24(name, arg) __builtin_##name(arg) +typedef unsigned int zig_Builtin24; +#define zig_builtin48(name, arg) __builtin_##name(arg) +typedef unsigned long long zig_Builtin48; +#endif + +static inline uint8_t zig_byteSwap_u8(uint8_t arg, uint8_t bits) { + return zig_u8_truncate_u8(arg >> (8 - bits), bits); } -static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits); +static inline int8_t zig_byteSwap_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_byteSwap_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bswap16) || defined(zig_gcc) - full_res = __builtin_bswap16(val); + full_res = __builtin_bswap16(arg); #else - full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits); +static inline int16_t zig_byteSwap_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_byteSwap_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint16_t zig_byte_swap_u24(uint24_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bswap24) || defined(zig_gcc) - full_res = __builtin_bswap24(val); + full_res = __builtin_bswap24(arg); #else - full_res = (uint24_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_byte_swap_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_byteSwap_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int16_t zig_byte_swap_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_byte_swap_u24((uint24_t)val, bits), bits); +static inline int16_t zig_byteSwap_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_byteSwap_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bswap32) || defined(zig_gcc) - full_res = __builtin_bswap32(val); + full_res = __builtin_bswap32(arg); #else - full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits); +static inline int32_t zig_byteSwap_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_byteSwap_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_byte_swap_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bswap48) || defined(zig_gcc) - full_res = __builtin_bswap48(val); + full_res = __builtin_bswap48(arg); #else - full_res = (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u48(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_byte_swap_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_byte_swap_u48((uint48_t)val, bits), bits); +static inline int32_t zig_byteSwap_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_byteSwap_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_byteSwap_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bswap64) || defined(zig_gcc) - full_res = __builtin_bswap64(val); + full_res = __builtin_bswap64(arg); #else - full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits); +static inline int64_t zig_byteSwap_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_byteSwap_u64((uint64_t)arg, bits), bits); } -static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) { +static inline uint8_t zig_bitReverse_u8(uint8_t arg, uint8_t bits) { uint8_t full_res; #if zig_has_builtin(bitreverse8) - full_res = __builtin_bitreverse8(val); + full_res = __builtin_bitreverse8(arg); #else static uint8_t const lut[0x10] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; + full_res = lut[arg >> 0 & 0xF] << 4 | lut[arg >> 4 & 0xF] << 0; #endif - return zig_wrap_u8(full_res >> (8 - bits), bits); + return zig_u8_truncate_u8(full_res >> (8 - bits), bits); } -static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits); +static inline int8_t zig_bitReverse_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_bitReverse_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_bitReverse_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bitreverse16) - full_res = __builtin_bitreverse16(val); + full_res = __builtin_bitreverse16(arg); #else - full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits); +static inline int16_t zig_bitReverse_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_bitReverse_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint24_t zig_bit_reverse_u24(uint24_t val, uint8_t bits) { +static inline uint24_t zig_bitReverse_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bitreverse24) - full_res = __builtin_bitreverse24(val); + full_res = __builtin_bitreverse24(arg); #else - full_res = (uint24_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_bit_reverse_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_bitReverse_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int24_t zig_bit_reverse_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_bit_reverse_u24((uint24_t)val, bits), bits); +static inline int24_t zig_bitReverse_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_bitReverse_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bitreverse32) - full_res = __builtin_bitreverse32(val); + full_res = __builtin_bitreverse32(arg); #else - full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits); +static inline int32_t zig_bitReverse_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_bitReverse_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_bit_reverse_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bitreverse48) - full_res = __builtin_bitreverse48(val); + full_res = __builtin_bitreverse48(arg); #else - full_res = (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u32(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_bit_reverse_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_bit_reverse_u48((uint48_t)val, bits), bits); +static inline int32_t zig_bitReverse_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_bitReverse_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_bitReverse_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bitreverse64) - full_res = __builtin_bitreverse64(val); + full_res = __builtin_bitreverse64(arg); #else - full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits); +static inline int64_t zig_bitReverse_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_bitReverse_u64((uint64_t)arg, bits), bits); } -#define zig_builtin_popcount_common(w) \ - static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w((uint##w##_t)val, bits); \ +#define zig_builtin_popCount_common(w) \ + static inline uint8_t zig_popCount_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w((uint##w##_t)arg, bits); \ } -#if zig_has_builtin(popcount) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#if zig_has_builtin(popCount) || defined(zig_gcc) || defined(zig_tinyc) +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - return zig_builtin##w(popcount, val); \ + return zig_builtin##w(popcount, arg); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #else -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \ + uint##w##_t temp = arg - ((arg >> 1) & (UINT##w##_MAX / 3)); \ temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \ temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \ return temp * (UINT##w##_MAX / 255) >> (UINT8_C(w) - UINT8_C(8)); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #endif -zig_builtin_popcount(8) -zig_builtin_popcount(16) +zig_builtin_popCount(8) +zig_builtin_popCount(16) +zig_builtin_popCount(32) +zig_builtin_popCount(64) #if defined(zig_ez80) -zig_builtin_popcount(24) +zig_builtin_popCount(24) +zig_builtin_popCount(48) #endif -zig_builtin_popcount(32) -#if defined(zig_ez80) -zig_builtin_popcount(48) -#endif -zig_builtin_popcount(64) #define zig_builtin_ctz_common(w) \ - static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_ctz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(ctz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(ctz, val); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(ctz, arg); \ } \ \ zig_builtin_ctz_common(w) #else #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w(zig_not_u##w(arg, bits) & zig_subw_u##w(arg, 1, bits), bits); \ } \ \ zig_builtin_ctz_common(w) #endif zig_builtin_ctz(8) zig_builtin_ctz(16) -#if defined(zig_ez80) -zig_builtin_ctz(24) -#endif zig_builtin_ctz(32) -#if defined(zig_ez80) -zig_builtin_ctz(48) -#endif zig_builtin_ctz(64) +#if defined(zig_ez80) +zig_builtin_ctz(24) +zig_builtin_ctz(48) +#endif #define zig_builtin_clz_common(w) \ - static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_clz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_clz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_clz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(clz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(clz, arg) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ } \ \ zig_builtin_clz_common(w) #else #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w(zig_bitReverse_u##w(arg, bits), bits); \ } \ \ zig_builtin_clz_common(w) #endif zig_builtin_clz(8) zig_builtin_clz(16) -#if defined(zig_ez80) -zig_builtin_clz(24) -#endif zig_builtin_clz(32) -#if defined(zig_ez80) -zig_builtin_clz(48) -#endif zig_builtin_clz(64) +#if defined(zig_ez80) +zig_builtin_clz(24) +zig_builtin_clz(48) +#endif /* ======================== 128-bit Integer Support ========================= */ @@ -1816,16 +1980,14 @@ zig_builtin_clz(64) typedef unsigned __int128 zig_u128; typedef signed __int128 zig_i128; -#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) -#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#define zig_hi_u128(val) ((uint64_t)((val) >> 64)) -#define zig_lo_u128(val) ((uint64_t)((val) >> 0)) -#define zig_hi_i128(val) (( int64_t)((val) >> 64)) -#define zig_lo_i128(val) ((uint64_t)((val) >> 0)) -#define zig_bitCast_u128(val) ((zig_u128)(val)) -#define zig_bitCast_i128(val) ((zig_i128)(val)) +#define zig_init_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) +#define zig_init_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) +#define zig_make_u128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) zig_init_i128(hi, lo) +#define zig_hi_u128(arg) ((uint64_t)((arg) >> 64)) +#define zig_lo_u128(arg) ((uint64_t)((arg) >> 0)) +#define zig_hi_i128(arg) (( int64_t)((arg) >> 64)) +#define zig_lo_i128(arg) ((uint64_t)((arg) >> 0)) #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs > rhs) - (lhs < rhs); \ @@ -1835,32 +1997,49 @@ typedef signed __int128 zig_i128; return lhs operator rhs; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + return lhs >> rhs; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + // This works around a GCC miscompilation, but it has the side benefit of + // emitting better code. It is behind the `#if` because it depends on + // arithmetic right shift, which is implementation-defined in C, but should + // be guaranteed on any GCC-compatible compiler. +#if defined(zig_gnuc) + return lhs >> rhs; +#else + zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); + return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; +#endif +} + #else /* zig_has_int128 */ #if zig_little_endian -typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; -typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; uint64_t hi; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; int64_t hi; } zig_i128; #else -typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128; -typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t hi; uint64_t lo; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) int64_t hi; uint64_t lo; } zig_i128; #endif -#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) -#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) - -#if defined(zig_msvc) /* MSVC doesn't allow struct literals in constant expressions */ -#define zig_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#define zig_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#else /* But non-MSVC doesn't like the unprotected commas */ -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#endif -#define zig_hi_u128(val) ((val).hi) -#define zig_lo_u128(val) ((val).lo) -#define zig_hi_i128(val) ((val).hi) -#define zig_lo_i128(val) ((val).lo) -#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo) -#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo) +#define zig_init_u128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_init_i128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_make_u128(hi, lo) (zig_u128)zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) (zig_i128)zig_init_i128(hi, lo) +#define zig_hi_u128(arg) (arg).hi +#define zig_lo_u128(arg) (arg).lo +#define zig_hi_i128(arg) (arg).hi +#define zig_lo_i128(arg) (arg).lo #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs.hi == rhs.hi) \ @@ -1872,6 +2051,30 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; + return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; + return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; +} + #endif /* zig_has_int128 */ #define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64) @@ -1891,42 +2094,177 @@ zig_bit_int128(i128, or, |) zig_bit_int128(u128, xor, ^) zig_bit_int128(i128, xor, ^) -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs); +static inline uint8_t zig_u8_intCast_u128(zig_u128 arg) { + return (uint8_t)zig_lo_u128(arg); +} +static inline uint8_t zig_u8_intCast_i128(zig_i128 arg) { + return (uint8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_i128(zig_i128 arg) { + return (int8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_u128(zig_u128 arg) { + return (int8_t)zig_lo_u128(arg); +} -#if zig_has_int128 +static inline uint16_t zig_u16_intCast_u128(zig_u128 arg) { + return (uint16_t)zig_lo_u128(arg); +} +static inline uint16_t zig_u16_intCast_i128(zig_i128 arg) { + return (uint16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_i128(zig_i128 arg) { + return (int16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_u128(zig_u128 arg) { + return (int16_t)zig_lo_u128(arg); +} -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return val ^ zig_maxInt_u(128, bits); +static inline uint32_t zig_u32_intCast_u128(zig_u128 arg) { + return (uint32_t)zig_lo_u128(arg); +} +static inline uint32_t zig_u32_intCast_i128(zig_i128 arg) { + return (uint32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_i128(zig_i128 arg) { + return (int32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_u128(zig_u128 arg) { + return (int32_t)zig_lo_u128(arg); } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - (void)bits; - return ~val; +static inline uint64_t zig_u64_intCast_u128(zig_u128 arg) { + return zig_lo_u128(arg); +} +static inline uint64_t zig_u64_intCast_i128(zig_i128 arg) { + return zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_i128(zig_i128 arg) { + return (int64_t)zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_u128(zig_u128 arg) { + return (int64_t)zig_lo_u128(arg); +} + +static inline zig_u128 zig_u128_intCast_u8(uint8_t arg) { + return zig_make_u128(UINT8_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i8(int8_t arg) { + return zig_make_u128(UINT8_C(0), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_i8(int8_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_u8(uint8_t arg) { + return zig_make_i128(INT8_C(0), arg); } -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u16(uint16_t arg) { + return zig_make_u128(UINT16_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i16(int16_t arg) { + return zig_make_u128(UINT16_C(0), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_i16(int16_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_u16(uint16_t arg) { + return zig_make_i128(INT16_C(0), arg); } -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - return lhs << rhs; +static inline zig_u128 zig_u128_intCast_u32(uint32_t arg) { + return zig_make_u128(UINT32_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i32(int32_t arg) { + return zig_make_u128(UINT32_C(0), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_i32(int32_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_u32(uint32_t arg) { + return zig_make_i128(INT32_C(0), arg); } -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - // This works around a GCC miscompilation, but it has the side benefit of - // emitting better code. It is behind the `#if` because it depends on - // arithmetic right shift, which is implementation-defined in C, but should - // be guaranteed on any GCC-compatible compiler. -#if defined(zig_gnuc) - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u64(uint64_t arg) { + return zig_make_u128(UINT64_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i64(int64_t arg) { + return zig_make_u128(UINT64_C(0), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_i64(int64_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_u64(uint64_t arg) { + return zig_make_i128(INT64_C(0), arg); +} + +static inline zig_u128 zig_u128_intCast_u128(zig_u128 arg) { + return arg; +} +static inline zig_u128 zig_u128_intCast_i128(zig_i128 arg) { +#if zig_has_int128 + return (zig_u128)arg; +#else + return zig_make_u128(zig_u64_bitCast_i64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); +#endif +} +static inline zig_i128 zig_i128_intCast_i128(zig_i128 arg) { + return arg; +} +static inline zig_i128 zig_i128_intCast_u128(zig_u128 arg) { +#if zig_has_int128 + return (zig_i128)arg; #else - zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; + return zig_make_i128(zig_i64_bitCast_u64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); #endif } -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - return lhs << rhs; +#define zig_int128_cast_builtins(w) \ + static inline uint##w##_t zig_u##w##_truncate_u128(zig_u128 arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w((uint##w##_t)zig_lo_u128(arg), bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_truncate_i128(zig_i128 arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w((int##w##_t)zig_lo_i128(arg), bits); \ + } +zig_int128_cast_builtins(8) +zig_int128_cast_builtins(16) +zig_int128_cast_builtins(32) +zig_int128_cast_builtins(64) + +static inline zig_u128 zig_u128_truncate_u128(zig_u128 arg, uint8_t bits) { + return zig_and_u128(arg, zig_maxInt_u(128, bits)); +} +static inline zig_i128 zig_i128_truncate_i128(zig_i128 arg, uint8_t bits) { + if (bits > UINT8_C(64)) return zig_make_i128(zig_i64_truncate_i64(zig_hi_i128(arg), bits - UINT8_C(64)), zig_lo_i128(arg)); + int64_t lo = zig_i64_truncate_i128(arg, bits); + return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); +} + +static inline zig_u128 zig_u128_bitCast_u128(zig_u128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_u128 zig_u128_bitCast_i128(zig_i128 arg, uint8_t bits) { + return zig_u128_truncate_u128(zig_u128_intCast_i128(arg), bits); +} +static inline zig_i128 zig_i128_bitCast_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_i128 zig_i128_bitCast_u128(zig_u128 arg, uint8_t bits) { + return zig_i128_truncate_i128(zig_i128_intCast_u128(arg), bits); +} + +#if zig_has_int128 + +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + return arg ^ zig_maxInt_u(128, bits); +} + +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return ~arg; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -1953,11 +2291,11 @@ static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { return lhs * rhs; } -static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { return lhs / rhs; } -static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { return lhs / rhs; } @@ -1971,36 +2309,14 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { #else /* zig_has_int128 */ -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return (zig_u128){ .hi = UINT64_C(0), .lo = zig_not_u64(arg.lo, bits) }; + return (zig_u128){ .hi = zig_not_u64(arg.hi, bits - UINT8_C(64)), .lo = zig_not_u64(arg.lo, UINT8_C(64)) }; } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; - return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; - return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return (zig_i128){ .hi = ~arg.hi, .lo = ~arg.lo }; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -2027,59 +2343,59 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { return res; } -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); return __multi3(lhs, rhs); } static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs))); + return zig_u128_bitCast_i128(zig_mul_i128(zig_i128_bitCast_u128(lhs, UINT8_C(128)), zig_i128_bitCast_u128(rhs, UINT8_C(128))), UINT8_C(128)); } -zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); return __udivti3(lhs, rhs); } -zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); return __divti3(lhs, rhs); } -zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); return __umodti3(lhs, rhs); } -zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); return __modti3(lhs, rhs); } #endif /* zig_has_int128 */ -#define zig_div_floor_u128 zig_div_trunc_u128 +#define zig_divFloor_u128 zig_divTrunc_u128 -static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divFloor_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); } -static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divCeil_u128(zig_u128 lhs, zig_u128 rhs) { zig_u128 rem = zig_rem_u128(lhs, rhs); uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) ? UINT64_C(1) : UINT64_C(0); - return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); + return zig_add_u128(zig_divTrunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); } -static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divCeil_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); } #define zig_mod_u128 zig_rem_u128 @@ -2107,51 +2423,41 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs; } -static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) { - return zig_and_u128(val, zig_maxInt_u(128, bits)); -} - -static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) { - if (bits > UINT8_C(64)) return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val)); - int64_t lo = zig_wrap_i64((int64_t)zig_lo_i128(val), bits); - return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); -} - static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_shl_u128(lhs, rhs), bits); } static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_shl_u128(zig_u128_bitCast_i128(lhs, bits), rhs), bits), bits); } static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_add_u128(lhs, rhs), bits); } static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_add_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_sub_u128(lhs, rhs), bits); } static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_sub_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_mul_u128(lhs, rhs), bits); } static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_mul_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } -static inline zig_u128 zig_abs_i128(zig_i128 val) { - zig_i128 tmp = zig_shr_i128(val, 127); - return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp)); +static inline zig_u128 zig_abs_i128(zig_i128 arg) { + zig_u128 tmp = zig_u128_bitCast_i128(zig_shr_i128(arg, 127), UINT8_C(128)); + return zig_sub_u128(zig_xor_u128(zig_u128_bitCast_i128(arg, UINT8_C(128)), tmp), tmp); } #if zig_has_int128 @@ -2160,7 +2466,7 @@ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(add_overflow) zig_u128 full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_addw_u128(lhs, rhs, bits); @@ -2176,7 +2482,7 @@ static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs + (zig_u128)rhs); bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2184,7 +2490,7 @@ static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(sub_overflow) zig_u128 full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_subw_u128(lhs, rhs, bits); @@ -2200,7 +2506,7 @@ static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs - (zig_u128)rhs); bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2208,7 +2514,7 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(mul_overflow) zig_u128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_mulw_u128(lhs, rhs, bits); @@ -2216,8 +2522,8 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #endif } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); #if zig_has_builtin(mul_overflow) zig_i128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -2226,50 +2532,78 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } #else /* zig_has_int128 */ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_addo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_addo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_subo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_subo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { *res = zig_mulw_u128(lhs, rhs, bits); - return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) && - zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); + return zig_cmp_u128(rhs, zig_make_u128(0, 0)) != INT32_C(0) && + zig_cmp_u128(lhs, zig_divTrunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); int overflow_int; zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0 || zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) || zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0); - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow; } @@ -2282,28 +2616,54 @@ static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8 static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) { *res = zig_shlw_i128(lhs, rhs, bits); - zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1))); + zig_i128 mask = zig_i128_bitCast_u128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)), bits); return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) && zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0); } -static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { +#define zig_int128_shls_builtins(rw) \ + static inline zig_u128 zig_shls_u128_u##rw(zig_u128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_u128 res; \ + if (rhs < bits && !zig_shlo_u128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_u128(lhs, zig_make_u128(UINT64_C(0), UINT64_C(0)))) { \ + case 0: return zig_minInt_u(128, bits); \ + case 1: return zig_maxInt_u(128, bits); \ + default: zig_unreachable(); \ + } \ + } \ +\ + static inline zig_i128 zig_shls_i128_u##rw(zig_i128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_i128 res; \ + if (rhs < bits && !zig_shlo_i128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_i128(lhs, zig_make_i128(INT64_C(0), UINT64_C(0)))) { \ + case -1: return zig_minInt_i(128, bits); \ + case 0: return zig_make_i128(INT64_C(0), UINT64_C(0)); \ + case 1: return zig_maxInt_i(128, bits); \ + default: zig_unreachable(); \ + } \ + } +zig_int128_shls_builtins(8) +zig_int128_shls_builtins(16) +zig_int128_shls_builtins(32) +zig_int128_shls_builtins(64) + +static inline zig_u128 zig_shls_u128_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { zig_u128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_u128(lhs, zig_make_u128(0, 0))) { - case 0: return zig_make_u128(0, 0); - case 1: return zig_maxInt_u(128, bits); + case INT32_C(0): return zig_make_u128(0, 0); + case INT32_C(1): return zig_maxInt_u(128, bits); default: zig_unreachable(); } } -static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { +static inline zig_i128 zig_shls_i128_u128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { zig_i128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_i128(lhs, zig_make_i128(0, 0))) { - case -1: return zig_minInt_i(128, bits); - case 0: return zig_make_i128(0, 0); - case 1: return zig_maxInt_i(128, bits); + case -INT32_C(1): return zig_minInt_i(128, bits); + case INT32_C(0): return zig_make_i128(0, 0); + case INT32_C(1): return zig_maxInt_i(128, bits); default: zig_unreachable(); } } @@ -2341,57 +2701,60 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); } -static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) { - if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits); - if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64)); - return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64)); +static inline uint8_t zig_clz_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(arg), bits); + if (zig_hi_u128(arg) != 0) return zig_clz_u64(zig_hi_u128(arg), bits - UINT8_C(64)); + return zig_clz_u64(zig_lo_u128(arg), UINT8_C(64)) + (bits - UINT8_C(64)); } -static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) { - return zig_clz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_clz_i128(zig_i128 arg, uint8_t bits) { + return zig_clz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) { - if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64)); - return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64); +static inline uint8_t zig_ctz_u128(zig_u128 arg, uint8_t bits) { + if (zig_lo_u128(arg) != 0) return zig_ctz_u64(zig_lo_u128(arg), UINT8_C(64)); + return zig_ctz_u64(zig_hi_u128(arg), bits - UINT8_C(64)) + UINT8_C(64); } -static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) { - return zig_ctz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_ctz_i128(zig_i128 arg, uint8_t bits) { + return zig_ctz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) { - return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) + - zig_popcount_u64(zig_lo_u128(val), UINT8_C(64)); +static inline uint8_t zig_popCount_u128(zig_u128 arg, uint8_t bits) { + return (bits > UINT8_C(64) ? zig_popCount_u64(zig_hi_u128(arg), bits - UINT8_C(64)) : UINT8_C(0)) + + zig_popCount_u64(zig_lo_u128(arg), UINT8_C(64)); } -static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) { - return zig_popcount_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_popCount_i128(zig_i128 arg, uint8_t bits) { + return zig_popCount_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) { +static inline zig_u128 zig_byteSwap_u128(zig_u128 arg, uint8_t bits) { zig_u128 full_res; #if zig_has_builtin(bswap128) - full_res = __builtin_bswap128(val); + full_res = __builtin_bswap128(arg); #else - full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)), - zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64))); + full_res = zig_make_u128( + zig_byteSwap_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_byteSwap_u64(zig_hi_u128(arg), UINT8_C(64)) + ); #endif return zig_shr_u128(full_res, UINT8_C(128) - bits); } -static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_byteSwap_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_byteSwap_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } -static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) { - return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)), - zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))), - UINT8_C(128) - bits); +static inline zig_u128 zig_bitReverse_u128(zig_u128 arg, uint8_t bits) { + return zig_shr_u128(zig_make_u128( + zig_bitReverse_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_bitReverse_u64(zig_hi_u128(arg), UINT8_C(64)) + ), UINT8_C(128) - bits); } -static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_bitReverse_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_bitReverse_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } #if zig_has_int128 @@ -2411,12 +2774,378 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { /* ========================== Big Integer Support =========================== */ static inline uint16_t zig_int_bytes(uint16_t bits) { - uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; + uint16_t bytes = (bits - UINT16_C(1)) / CHAR_BIT + UINT16_C(1); uint16_t alignment = ZIG_TARGET_MAX_INT_ALIGNMENT; + while (alignment / 2 >= bytes) alignment /= 2; return (bytes + alignment - 1) / alignment * alignment; } +static inline void zig_minInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_minInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_minInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_minInt_u8, size - byte_offset); +#endif +} + +static inline void zig_maxInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_maxInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_maxInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_maxInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_maxInt_u8, size - byte_offset); +#endif +} + +static inline int8_t zig_signFill_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + + if (!is_signed) return INT8_C(0); +#if zig_little_endian + byte_offset = zig_int_bytes(bits) - 1; +#endif + return zig_shr_i8(zig_i8_bitCast_u8(arg_bytes[byte_offset], UINT8_C(8)), UINT8_C(7)); +} + +static inline void zig_big_intCast_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + uint16_t arg_size = zig_int_bytes(arg_bits); + uint16_t copy_size = zig_min_u16(res_size, arg_size); + uint8_t sign_fill = zig_u8_bitCast_i8(zig_signFill_big(arg, arg_is_signed, arg_bits), UINT8_C(8)); + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], copy_size); + memset(&res_bytes[copy_size], sign_fill, res_size - copy_size); +#else + memset(&res_bytes[0], sign_fill, res_size - copy_size); + memcpy(&res_bytes[res_size - copy_size], &arg_bytes[arg_size - copy_size], copy_size); +#endif +} + +static inline void zig_big_truncate_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + + if (res_is_signed != arg_is_signed) zig_unreachable(); + if (res_bits > arg_bits) zig_unreachable(); + + if (res_is_signed) { + uint16_t arg_byte_offset = UINT16_C(0); + +#if zig_big_endian + arg_byte_offset = zig_int_bytes(arg_bits) - res_size; +#endif + + memcpy(&res_bytes[0], &arg_bytes[arg_byte_offset], res_size); + } else { + uint16_t res_byte_offset = zig_shr_u16(res_bits - UINT16_C(1), UINT8_C(3)); + uint16_t arg_byte_offset = res_byte_offset; + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], res_byte_offset); +#else + res_byte_offset = res_size - UINT16_C(1) - res_byte_offset; + arg_byte_offset = zig_int_bytes(arg_bits) - UINT16_C(1) - arg_byte_offset; + + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + + res_bytes[res_byte_offset] = zig_u8_truncate_u8( + arg_bytes[arg_byte_offset], + zig_u8_truncate_u8(res_bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1) + ); + res_byte_offset += UINT16_C(1); + arg_byte_offset += UINT16_C(1); + +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, res_size - res_byte_offset); +#else + memcpy(&res_bytes[res_byte_offset], &arg_bytes[arg_byte_offset], res_size - res_byte_offset); +#endif + } +} + +#define zig_big_casts(is, s, w, IntType) \ + static inline IntType zig_##s##w##_intCast_big(const void *arg, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_intCast_big(&res, arg, is, w, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_intCast_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_intCast_big(res, &arg, res_is_signed, res_bits, is, w); \ + } \ +\ + static inline IntType zig_##s##w##_truncate_big(const void *arg, uint8_t res_bits, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_truncate_big(&res, arg, is, res_bits, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_truncate_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_truncate_big(res, &arg, res_is_signed, res_bits, is, w); \ + } +zig_big_casts(false, u, 8, uint8_t) +zig_big_casts(true , i, 8, int8_t) +zig_big_casts(false, u, 16, uint16_t) +zig_big_casts(true , i, 16, int16_t) +zig_big_casts(false, u, 32, uint32_t) +zig_big_casts(true , i, 32, int32_t) +zig_big_casts(false, u, 64, uint64_t) +zig_big_casts(true , i, 64, int64_t) +zig_big_casts(false, u, 128, zig_u128) +zig_big_casts(true , i, 128, zig_i128) + +static inline void zig_big_bitCast_big(void *res, const void *arg, bool res_is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + +#if zig_big_endian + byte_offset = size - UINT16_C(1) - byte_offset; +#endif + + if (res_is_signed) { + int8_t signed_sign_byte = zig_i8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_u8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memcpy(&res_bytes[byte_offset], &arg_bytes[byte_offset], size - byte_offset); +#endif +} + +static inline int32_t zig_cmp_big_u8(const void *lhs, uint8_t rhs, bool is_signed, uint16_t bits) { + const uint8_t *lhs_bytes = lhs; + uint16_t byte_offset = 0; + bool do_signed = is_signed; + uint16_t remaining_bytes = zig_int_bytes(bits); + +#if zig_little_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 128 / CHAR_BIT ? rhs : UINT8_C(0); + int32_t limb_cmp; + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (do_signed) { + zig_i128 lhs_limb; + zig_i128 rhs_limb = zig_i128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); + do_signed = false; + } else { + zig_u128 lhs_limb; + zig_u128 rhs_limb = zig_u128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); + } + + if (limb_cmp != 0) return limb_cmp; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 64 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (do_signed) { + int64_t lhs_limb; + int64_t rhs_limb = zig_i64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint64_t lhs_limb; + uint64_t rhs_limb = zig_u64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 32 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (do_signed) { + int32_t lhs_limb; + int32_t rhs_limb = zig_i32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint32_t lhs_limb; + uint32_t rhs_limb = zig_u32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (do_signed) { + int16_t lhs_limb; + int16_t rhs_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint16_t lhs_limb; + uint16_t rhs_limb = zig_u16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (do_signed) { + int8_t lhs_limb; + int16_t lhs_cmp_limb; + int16_t rhs_cmp_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + lhs_cmp_limb = zig_i16_intCast_i8(lhs_limb); + if (lhs_cmp_limb != rhs_cmp_limb) return (lhs_cmp_limb > rhs_cmp_limb) - (lhs_cmp_limb < rhs_cmp_limb); + do_signed = false; + } else { + uint8_t lhs_limb; + uint8_t rhs_limb = rhs_byte; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return 0; +} + static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; @@ -2579,6 +3308,168 @@ static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_sign return 0; } +static inline void zig_not_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (remaining_bytes != 128 / CHAR_BIT || is_signed) { + zig_i128 res_limb; + zig_i128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (remaining_bytes != 64 / CHAR_BIT || is_signed) { + int64_t res_limb; + int64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (remaining_bytes != 32 / CHAR_BIT || is_signed) { + int32_t res_limb; + int32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (remaining_bytes != 16 / CHAR_BIT || is_signed) { + int16_t res_limb; + int16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (remaining_bytes != 8 / CHAR_BIT || is_signed) { + int8_t res_limb; + int8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; @@ -2816,13 +3707,415 @@ static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool } } +static inline void zig_increment_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_decrement_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_abs_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + if (zig_signFill_big(arg, is_signed, bits) >= INT8_C(0)) { + memcpy(res, arg, remaining_bytes); + return; + } + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool overflow = true; + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u128(&res_limb, zig_not_u128(arg_limb, UINT8_C(128)), zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u64(&res_limb, zig_not_u64(arg_limb, UINT8_C(64)), overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u32(&res_limb, zig_not_u32(arg_limb, UINT8_C(32)), overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u16(&res_limb, zig_not_u16(arg_limb, UINT8_C(16)), overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u8(&res_limb, zig_not_u8(arg_limb, UINT8_C(8)), overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_min_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) < INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + +static inline void zig_max_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) >= INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3038,7 +4331,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3248,323 +4541,755 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo return overflow; } +static inline void zig_add_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_addo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_addw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_addo_big(res, lhs, rhs, is_signed, bits); } +static inline void zig_adds_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits); + + if (!zig_addo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } +} + +static inline void zig_sub_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_subo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_subo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __udivei4(res, lhs, rhs, bits); - return; - } +static inline void zig_subs_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = is_signed ? zig_signFill_big(lhs, is_signed, bits) : -INT8_C(1); - zig_trap(); + if (!zig_subo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } } -static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_div_trunc_big(res, lhs, rhs, is_signed, bits); - return; +static inline bool zig_mulo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + const uint8_t *rhs_bytes = rhs; + uint16_t size = zig_int_bytes(bits); + uint16_t sign_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint8_t rhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(rhs, is_signed, bits), UINT8_C(8)); + uint16_t lhs_byte_offset = sign_byte_offset; + uint16_t lhs_end_byte_offset = UINT16_C(0); + bool overflow = false; + +#if zig_big_endian + lhs_byte_offset = size - lhs_byte_offset; + lhs_end_byte_offset = size - lhs_end_byte_offset; +#endif + + while (lhs_byte_offset != lhs_end_byte_offset) { + uint16_t rhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint16_t res_byte_offset; + uint16_t lhs_byte; + uint8_t res_byte = UINT8_C(0); + uint16_t mul_res = UINT16_C(0); + uint8_t carry = UINT8_C(0); + +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#else + rhs_byte_offset = size - rhs_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + + lhs_byte = zig_u16_intCast_u8(lhs_bytes[lhs_byte_offset]) ^ lhs_sign_fill; + +#if zig_big_endian + lhs_byte_offset += UINT16_C(1); +#endif + + res_byte_offset = lhs_byte_offset; + + while (res_byte_offset != end_byte_offset) { + bool res_byte_initialized = res_byte_offset != lhs_byte_offset; + +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); + res_byte_offset -= UINT16_C(1); +#endif + + if (res_byte_initialized) res_byte = res_bytes[res_byte_offset]; + carry = zig_addo_u8(&res_byte, res_byte, carry, UINT8_C(8)); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_intCast_u16( + zig_shr_u16(mul_res, UINT8_C(8)) + ), UINT8_C(8)); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_bytes[res_byte_offset], res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); + res_byte_offset += UINT16_C(1); +#endif + } + + while (rhs_byte_offset != end_byte_offset) { +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); +#endif + + carry = zig_addo_u8( + &res_byte, + zig_u8_intCast_u16(zig_shr_u16(mul_res, UINT8_C(8))), + carry, + UINT8_C(8) + ); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + overflow |= res_byte != UINT8_C(0); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); +#endif + } + + overflow |= zig_shr_u16(mul_res, UINT8_C(8)) != UINT16_C(0); + overflow |= carry != UINT8_C(0); } - zig_trap(); +#if zig_little_endian + sign_byte_offset -= UINT64_C(1); +#else + sign_byte_offset = size - sign_byte_offset; +#endif + + if (lhs_sign_fill != rhs_sign_fill) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(0); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, UINT8_C(0), carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, res_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8( + &res_bytes[byte_offset], + res_byte, + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, INT8_C(0), signed_res_byte, UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (lhs_sign_fill != UINT8_C(0)) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(1); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, res_bytes[byte_offset], carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, lhs_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8(&res_bytes[byte_offset], res_byte, rhs_bytes[byte_offset], UINT8_C(8)); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + lhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + rhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (is_signed) { + int8_t signed_res_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + + overflow |= signed_res_byte < INT8_C(0); + } + + { + uint8_t truncate_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t fill_byte = UINT8_C(0); + + if (is_signed) { + int8_t sign_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + int8_t truncated = zig_i8_truncate_i8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + } else { + uint8_t sign_byte = res_bytes[sign_byte_offset]; + uint8_t truncated = zig_u8_truncate_u8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = truncated; + } + +#if zig_little_endian + sign_byte_offset += UINT16_C(1); + memset(&res_bytes[sign_byte_offset], fill_byte, size - sign_byte_offset); +#else + memset(&res_bytes[0], fill_byte, sign_byte_offset); +#endif + } + + return overflow; +} + +static inline void zig_mul_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_mulo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow } -static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - zig_trap(); +static inline void zig_mulw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + (void)zig_mulo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __umodei4(res, lhs, rhs, bits); - return; +static inline void zig_muls_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits) ^ zig_signFill_big(rhs, is_signed, bits); + + if (!zig_mulo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); } +} + +static inline void zig_divTrunc_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __divei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __divei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __udivei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __udivei5(res, lhs, rhs, temp, bits); + } +} - zig_trap(); +static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __modei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __modei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __umodei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __umodei5(res, lhs, rhs, temp, bits); + } } -static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_rem_big(res, lhs, rhs, is_signed, bits); - return; +static inline void zig_divFloor_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool decrement = false; + + if (is_signed) { + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + decrement = zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32)); } + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (decrement) zig_decrement_big(res, is_signed, bits); +} - zig_trap(); +static inline void zig_divCeil_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool increment = false; + + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + increment = zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ) > INT32_C(0); + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (increment) zig_increment_big(res, is_signed, bits); } -static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t skip_bits = remaining_bytes * 8 - bits; - uint16_t total_lz = 0; - uint16_t limb_lz; - (void)is_signed; +static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool fixup = false; -#if zig_little_endian - byte_offset = remaining_bytes; + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + if (is_signed && zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32))) zig_add_big(res, res, rhs, is_signed, bits); +} + +static inline void zig_shr_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t lhs_byte_offset = zig_shr_u16(rhs, UINT8_C(3)); + uint16_t end_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_prev_byte; + uint8_t byte_shift = zig_u8_truncate_u16(rhs, UINT8_C(3)); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + lhs_byte_offset = size - lhs_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - while (remaining_bytes >= 128 / CHAR_BIT) { + { +#if zig_big_endian + lhs_byte_offset -= UINT16_C(1); +#endif + + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; + #if zig_little_endian - byte_offset -= 128 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); +#endif + } + + while (lhs_byte_offset != end_byte_offset) { +#if zig_big_endian + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - zig_u128 val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u128(val_limb, 128 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_prev_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 128 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; + { + uint8_t lhs_sign_fill = UINT8_C(0); + +#if zig_big_endian + res_byte_offset -= UINT16_C(1); #endif - { - uint64_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(lhs_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u64(val_limb, 64 - skip_bits); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + lhs_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(lhs_prev_byte, byte_shift); } - total_lz += limb_lz; - if (limb_lz < 64 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], lhs_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], lhs_sign_fill, res_byte_offset); #endif } +} + +static inline bool zig_shlo_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t lhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = res_byte_offset - UINT16_C(1) - zig_shr_u16(rhs, UINT8_C(3)); + uint8_t lhs_prev_byte = lhs_sign_fill; + uint8_t byte_shift = UINT8_C(8) - zig_u8_truncate_u16(rhs, UINT8_C(3)); + bool overflow = false; - while (remaining_bytes >= 32 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 32 / CHAR_BIT; + lhs_byte_offset = size - lhs_byte_offset; +#else + res_byte_offset = size - res_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u32(val_limb, 32 - skip_bits); - } + while (lhs_byte_offset != end_byte_offset) { +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#endif - total_lz += limb_lz; - if (limb_lz < 32 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 32 / CHAR_BIT; + overflow |= lhs_prev_byte != lhs_sign_fill; + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; #if zig_big_endian - byte_offset += 32 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 16 / CHAR_BIT; + end_byte_offset = UINT16_C(0); +#else + end_byte_offset = size; +#endif + + { + bool lhs_more_bytes = lhs_byte_offset != end_byte_offset; + +#if zig_little_endian + if (lhs_more_bytes) lhs_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t lhs_byte = UINT8_C(0); + + if (lhs_more_bytes) lhs_byte = lhs_bytes[lhs_byte_offset]; + + if (is_signed) { + int16_t shifted = zig_shr_i16(zig_or_i16( + zig_shl_i16(zig_i16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_i16_intCast_u8(lhs_byte) + ), byte_shift); + int8_t truncated = zig_i8_truncate_i16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + uint8_t fill = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + + overflow |= zig_i16_intCast_i8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif + res_bytes[res_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + } else { + uint16_t shifted = zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift); + uint8_t truncated = zig_u8_truncate_u16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + + overflow |= zig_u16_intCast_u8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + res_bytes[res_byte_offset] = truncated; + } - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u16(val_limb, 16 - skip_bits); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 16 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_big_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + if (lhs_more_bytes) lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + while (lhs_byte_offset != end_byte_offset) { #if zig_little_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - uint8_t val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u8(val_limb, 8 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 8 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_big_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - return total_lz; -} + { +#if zig_little_endian + res_byte_offset -= UINT16_C(1); +#endif -static inline uint16_t zig_ctz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_tz = 0; - uint16_t limb_tz; - (void)is_signed; + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + byte_shift + )); #if zig_big_endian - byte_offset = remaining_bytes; + res_byte_offset += UINT16_C(1); #endif + } - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#else + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); #endif - { - zig_u128 val_limb; + return overflow; +} - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u128(val_limb, 128); - } +static inline void zig_shl_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + if (zig_shlo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: left shift overflowed bits +} - total_tz += limb_tz; - if (limb_tz < 128) return total_tz; - remaining_bytes -= 128 / CHAR_BIT; +static inline void zig_shlw_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + (void)zig_shlo_big(res, lhs, rhs, is_signed, bits); +} -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif +#define zig_big_shls_builtin(w) \ + static inline uint##w##_t zig_shls_u##w##_big(uint##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + uint##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_u##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? zig_minInt_u(w, lhs_bits) : zig_maxInt_u(w, lhs_bits); \ + } \ +\ + static inline int##w##_t zig_shls_i##w##_big(int##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + int##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_i##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ + lhs < INT##w##_C(0) ? zig_minInt_i(w, lhs_bits) : zig_maxInt_i(w, lhs_bits); \ + } \ +\ + static inline void zig_shls_big_u##w(void *res, const void *lhs, uint##w##_t rhs, bool is_signed, uint16_t bits) { \ + const uint8_t *lhs_bytes = lhs; \ + if (rhs < bits && !zig_shlo_big(res, lhs, zig_u16_intCast_u##w(rhs), is_signed, bits)) return; \ + switch (zig_cmp_big_u8(lhs, UINT8_C(0), is_signed, bits)) { \ + case -INT32_C(1): return zig_minInt_big(res, is_signed, bits); \ + case INT32_C(0): return zig_minInt_big(res, false, bits); \ + case INT32_C(1): return zig_maxInt_big(res, is_signed, bits); \ + default: zig_unreachable(); \ + } \ } +zig_big_shls_builtin(8) +zig_big_shls_builtin(16) +zig_big_shls_builtin(32) +zig_big_shls_builtin(64) + +static inline void zig_byteSwap_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = bits / CHAR_BIT; + uint16_t end_byte_offset = UINT16_C(1); + uint16_t size = zig_int_bytes(bits); - while (remaining_bytes >= 64 / CHAR_BIT) { #if zig_big_endian - byte_offset -= 64 / CHAR_BIT; + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u64(val_limb, 64); - } + while (arg_byte_offset != end_byte_offset) { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); +#endif - total_tz += limb_tz; - if (limb_tz < 64) return total_tz; - remaining_bytes -= 64 / CHAR_BIT; + res_bytes[res_byte_offset] = arg_bytes[arg_byte_offset]; #if zig_little_endian - byte_offset += 64 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; + { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); #endif { - uint32_t val_limb; + uint8_t byte = arg_bytes[arg_byte_offset]; + uint8_t fill = is_signed + ? zig_u8_bitCast_i8(zig_shr_i8(zig_i8_bitCast_u8(byte, UINT8_C(8)), UINT8_C(7)), UINT8_C(8)) + : UINT8_C(0); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u32(val_limb, 32); + res_bytes[res_byte_offset] = byte; + +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif } + } +} - total_tz += limb_tz; - if (limb_tz < 32) return total_tz; - remaining_bytes -= 32 / CHAR_BIT; +static inline void zig_bitReverse_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t end_byte_offset = UINT16_C(0); + uint8_t arg_prev_byte; + uint8_t byte_shift = zig_u8_intCast_u16(zig_subw_u16(UINT16_C(0), bits, UINT8_C(3))); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + { #if zig_little_endian - byte_offset += 32 / CHAR_BIT; + arg_byte_offset -= UINT16_C(1); +#endif + + arg_prev_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); + +#if zig_big_endian + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { + while (arg_byte_offset != end_byte_offset) { #if zig_big_endian - byte_offset -= 16 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); +#else + arg_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t arg_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u16(val_limb, 16); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(arg_byte), UINT8_C(8)), + zig_u16_intCast_u8(arg_prev_byte) + ), byte_shift)); + arg_prev_byte = arg_byte; } - total_tz += limb_tz; - if (limb_tz < 16) return total_tz; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_little_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + { + uint8_t arg_sign_fill = UINT8_C(0); + #if zig_big_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); #endif - { - uint8_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(arg_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u8(val_limb, 8); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + arg_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(arg_prev_byte, byte_shift); } - total_tz += limb_tz; - if (limb_tz < 8) return total_tz; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_little_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], arg_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], arg_sign_fill, res_byte_offset); #endif } - - return total_tz; } -static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; +static inline uint16_t zig_popCount_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); uint16_t total_pc = 0; (void)is_signed; #if zig_big_endian - byte_offset = remaining_bytes; + byte_offset = zig_int_bytes(bits); #endif while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 128 / CHAR_BIT; #endif { - zig_u128 val_limb; + zig_u128 arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u128(val_limb, 128); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 128 / CHAR_BIT; @@ -3575,15 +5300,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 64 / CHAR_BIT; #endif { - uint64_t val_limb; + uint64_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u64(val_limb, 64); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 64 / CHAR_BIT; @@ -3594,15 +5321,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 32 / CHAR_BIT; #endif { - uint32_t val_limb; + uint32_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u32(val_limb, 32); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 32 / CHAR_BIT; @@ -3613,15 +5342,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 16 / CHAR_BIT; #endif { - uint16_t val_limb; + uint16_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u16(val_limb, 16); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 16 / CHAR_BIT; @@ -3632,15 +5363,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 8 / CHAR_BIT; #endif { - uint8_t val_limb; + uint8_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u8(val_limb, 8); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 8 / CHAR_BIT; @@ -3653,6 +5386,274 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ return total_pc; } +static inline uint16_t zig_ctz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = UINT16_C(0); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + uint16_t total_tz = UINT16_C(0); + uint16_t limb_tz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits); +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_tz; +} + +static inline uint16_t zig_clz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t remaining_bytes = byte_offset; + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool sign_limb = true; + uint16_t total_lz = UINT16_C(0); + uint16_t limb_lz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits) - remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(128) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(64) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(32) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(16) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(8) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_lz; +} + /* ========================= Floating Point Support ========================= */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ @@ -3687,29 +5688,29 @@ long double __cdecl nanl(char const* input); #define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg) #define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) #else -#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr) -#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr) -#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr) -#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr) -#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr) +#define zig_make_special_f16(sign, name, arg, repr) zig_f16_bitCast_u16 (repr) +#define zig_make_special_f32(sign, name, arg, repr) zig_f32_bitCast_u32 (repr) +#define zig_make_special_f64(sign, name, arg, repr) zig_f64_bitCast_u64 (repr) +#define zig_make_special_f80(sign, name, arg, repr) zig_f80_bitCast_u128(repr) +#define zig_make_special_f128(sign, name, arg, repr) zig_f128_bitCast_u128(repr) #endif #define zig_has_f16 1 #define zig_libc_name_f16(name) __##name##h #define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) -#if FLT_MANT_DIG == 11 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT_MANT_DIG == 11 typedef float zig_f16; #define zig_make_f16(fp, repr) fp##f -#elif DBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && DBL_MANT_DIG == 11 typedef double zig_f16; #define zig_make_f16(fp, repr) fp -#elif LDBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && LDBL_MANT_DIG == 11 typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) typedef _Float16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 -#elif defined(__SIZEOF_FP16__) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && defined(__SIZEOF_FP16__) typedef __fp16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 #else @@ -3723,11 +5724,6 @@ typedef uint16_t zig_f16; #undef zig_init_special_f16 #define zig_init_special_f16(sign, name, arg, repr) repr #endif -#if defined(zig_darwin) && defined(zig_x86) -typedef uint16_t zig_compiler_rt_f16; -#else -typedef zig_f16 zig_compiler_rt_f16; -#endif #define zig_has_f32 1 #define zig_libc_name_f32(name) name##f @@ -3736,16 +5732,16 @@ typedef zig_f16 zig_compiler_rt_f16; #else #define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 24 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT_MANT_DIG == 24 typedef float zig_f32; #define zig_make_f32(fp, repr) fp##f -#elif DBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && DBL_MANT_DIG == 24 typedef double zig_f32; #define zig_make_f32(fp, repr) fp -#elif LDBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && LDBL_MANT_DIG == 24 typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l -#elif FLT32_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT32_MANT_DIG == 24 typedef _Float32 zig_f32; #define zig_make_f32(fp, repr) fp##f32 #else @@ -3768,19 +5764,19 @@ typedef uint32_t zig_f32; #else #define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 53 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT_MANT_DIG == 53 typedef float zig_f64; #define zig_make_f64(fp, repr) fp##f -#elif DBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && DBL_MANT_DIG == 53 typedef double zig_f64; #define zig_make_f64(fp, repr) fp -#elif LDBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && LDBL_MANT_DIG == 53 typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l -#elif FLT64_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT64_MANT_DIG == 53 typedef _Float64 zig_f64; #define zig_make_f64(fp, repr) fp##f64 -#elif FLT32X_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT32X_MANT_DIG == 53 typedef _Float32x zig_f64; #define zig_make_f64(fp, repr) fp##f32x #else @@ -3798,7 +5794,14 @@ typedef uint64_t zig_f64; #define zig_has_f80 1 #define zig_libc_name_f80(name) __##name##x #define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) -#if FLT_MANT_DIG == 64 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F80_ABI +#undef zig_has_f80 +typedef struct { uint64_t mantissa; uint16_t exponent; } zig_f80; +#define zig_init_repr_f80(mantissa, exponent) { .mant##issa = mantissa, .expo##nent = exponent } +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#define zig_mantissa_repr_f80(arg) (arg).mantissa +#define zig_exponent_repr_f80(arg) (arg).exponent +#elif FLT_MANT_DIG == 64 typedef float zig_f80; #define zig_make_f80(fp, repr) fp##f #elif DBL_MANT_DIG == 64 @@ -3818,68 +5821,91 @@ typedef __float80 zig_f80; #define zig_make_f80(fp, repr) fp##l #else #undef zig_has_f80 -#define zig_has_f80 0 -#define zig_repr_f80 u128 typedef zig_u128 zig_f80; +#define zig_init_repr_f80(mantissa, exponent) zig_init_u128(exponent, mantissa) +#define zig_make_repr_f80(mantissa, exponent) zig_make_u128(exponent, mantissa) +#define zig_mantissa_repr_f80(arg) zig_lo_u128(arg) +#define zig_exponent_repr_f80(arg) (uint16_t)zig_hi_u128(arg) +#endif +#ifndef zig_has_f80 +#define zig_has_f80 0 #define zig_make_f80(fp, repr) repr +#ifndef zig_make_repr_f80 +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#endif #undef zig_make_special_f80 #define zig_make_special_f80(sign, name, arg, repr) repr #undef zig_init_special_f80 #define zig_init_special_f80(sign, name, arg, repr) repr #endif -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif - #define zig_has_f128 1 -#define zig_libc_name_f128(name) name##q +#define zig_libc_name_f128(name) name##f128 #define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) -#if !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F128_ABI +#undef zig_has_f128 +#if zig_little_endian +typedef struct { uint64_t lo, hi; } zig_f128; +#else +typedef struct { uint64_t hi, lo; } zig_f128; +#endif +#define zig_init_repr_f128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_lo_repr_f128(arg) (arg).lo +#define zig_hi_repr_f128(arg) (arg).hi +#elif FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 +#elif DBL_MANT_DIG == 113 typedef double zig_f128; #define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 +#elif LDBL_MANT_DIG == 113 typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 +#elif FLT128_MANT_DIG == 113 typedef _Float128 zig_f128; #define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 +#elif FLT64X_MANT_DIG == 113 typedef _Float64x zig_f128; #define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) +#elif defined(__SIZEOF_FLOAT128__) typedef __float128 zig_f128; #define zig_make_f128(fp, repr) fp##q #undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg) #else #undef zig_has_f128 -#define zig_has_f128 0 -#undef zig_make_special_f128 -#undef zig_init_special_f128 -#if defined(zig_darwin) || defined(zig_aarch64) -typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64; -zig_basic_operator(zig_v2u64, xor_v2u64, ^) -#define zig_repr_f128 v2u64 -typedef zig_v2u64 zig_f128; -#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi } -#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128 -#define zig_make_f128(fp, repr) zig_make_f128_##repr -#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr +#if defined(zig_x86_64) && defined(ZIG_TARGET_ABI_MSVC) +#if defined(zig_msvc) && !defined(__clang__) +#include +typedef __m128i zig_f128; +#define zig_init_repr_f128(hi, lo) { .m128i_u64 = { lo, hi } } +#define zig_lo_repr_f128(arg) (arg).m128i_u64[0] +#define zig_hi_repr_f128(arg) (arg).m128i_u64[1] +#else +typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_f128; +#define zig_init_repr_f128(hi, lo) { lo, hi } +#define zig_lo_repr_f128(arg) (arg)[0] +#define zig_hi_repr_f128(arg) (arg)[1] +#endif #else -#define zig_repr_f128 u128 typedef zig_u128 zig_f128; +#define zig_init_repr_f128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_repr_f128(hi, lo) zig_make_u128(hi, lo) +#define zig_lo_repr_f128(arg) zig_lo_u128(arg) +#define zig_hi_repr_f128(arg) zig_hi_u128(arg) +#endif +#endif +#ifndef zig_has_f128 +#define zig_has_f128 0 #define zig_make_f128(fp, repr) repr +#ifndef zig_make_repr_f128 +#define zig_make_repr_f128(hi, lo) (zig_f128)zig_init_repr_f128(hi, lo) +#endif +#undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) repr +#undef zig_init_special_f128 #define zig_init_special_f128(sign, name, arg, repr) repr #endif -#endif #if !defined(zig_msvc) && defined(ZIG_TARGET_ABI_MSVC) /* Emulate msvc abi on a gnu compiler */ @@ -3892,84 +5918,141 @@ typedef zig_f128 zig_c_longdouble; typedef long double zig_c_longdouble; #endif -#define zig_bitCast_float(Type, ReprType) \ - static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \ - zig_##Type result; \ - memcpy(&result, &repr, sizeof(result)); \ - return result; \ +#if __AVR__ +typedef signed char zig_FloatCompareResult; +#elif defined(zig_aarch64) +typedef signed int zig_FloatCompareResult; +#elif __SIZEOF_LONG__ >= __SIZEOF_POINTER__ +typedef signed long zig_FloatCompareResult; +#else +typedef signed long long zig_FloatCompareResult; +#endif + +#define zig_bitCast_float(w, iw, UnsignedReprType, SignedReprType) \ + static inline zig_f##w zig_f##w##_bitCast_u##iw(UnsignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline zig_f##w zig_f##w##_bitCast_i##iw(SignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline UnsignedReprType zig_u##iw##_bitCast_f##w(zig_f##w arg) { \ + UnsignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_u##iw##_truncate_u##iw(res, w); \ + } \ + static inline SignedReprType zig_i##iw##_bitCast_f##w(zig_f##w arg) { \ + SignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_i##iw##_truncate_i##iw(res, w); \ + } +zig_bitCast_float(16, 16, uint16_t, int16_t) +zig_bitCast_float(32, 32, uint32_t, int32_t) +zig_bitCast_float(64, 64, uint64_t, int64_t) +#if zig_has_f80 +zig_bitCast_float(80, 128, zig_u128, zig_i128) +#else +static inline zig_f80 zig_f80_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f80(zig_lo_u128(arg), (uint16_t)zig_hi_u128(arg)); +} +static inline zig_f80 zig_f80_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f80(zig_lo_i128(arg), (uint16_t)zig_hi_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f80(zig_f80 arg) { + return zig_make_u128(zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +static inline zig_i128 zig_i128_bitCast_f80(zig_f80 arg) { + return zig_make_i128((int16_t)zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +#endif +static inline zig_f80 zig_f80_bitCast_big(const void *arg) { + return zig_f80_bitCast_u128(zig_u128_truncate_big(arg, UINT8_C(80), false, UINT16_C(80))); +} +static inline void zig_big_bitCast_f80(void *res, zig_f80 arg, bool res_is_signed, uint16_t res_bits) { + if (res_is_signed) { + zig_big_truncate_i128(res, zig_i128_bitCast_f80(arg), res_is_signed, res_bits); + } else { + zig_big_truncate_u128(res, zig_u128_bitCast_f80(arg), res_is_signed, res_bits); } -zig_bitCast_float(f16, uint16_t) -zig_bitCast_float(f32, uint32_t) -zig_bitCast_float(f64, uint64_t) -zig_bitCast_float(f80, zig_u128) -zig_bitCast_float(f128, zig_u128) +} +#if zig_has_f128 +zig_bitCast_float(128, 128, zig_u128, zig_i128) +#else +static inline zig_f128 zig_f128_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f128(zig_hi_u128(arg), zig_lo_u128(arg)); +} +static inline zig_f128 zig_f128_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f128((uint64_t)zig_hi_i128(arg), zig_lo_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f128(zig_f128 arg) { + return zig_make_u128(zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +static inline zig_i128 zig_i128_bitCast_f128(zig_f128 arg) { + return zig_make_i128((int64_t)zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +#endif -#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \ - zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \ +#define zig_convert_float_00(ResType, operation, ArgType, version) \ + zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType arg); \ + return zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(arg) +#define zig_convert_float_01(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_10(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_11(ResType, operation, ArgType, version) \ + return (ResType)arg +#define zig_convert_float(res_when, ResType, operation, arg_when, ArgType, version) \ static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \ - ResType res; \ - ExternResType extern_res; \ - ExternArgType extern_arg; \ - memcpy(&extern_arg, &arg, sizeof(extern_arg)); \ - extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \ - memcpy(&res, &extern_res, sizeof(res)); \ - return extern_res; \ + zig_expand_concat(zig_expand_concat(zig_convert_float_, zig_has_##res_when), \ + zig_has_##arg_when)(ResType, operation, ArgType, version); \ } -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2) -#ifdef __ARM_EABI__ +#define zig_convert_floats(SmallType, BigType) \ + zig_convert_float(SmallType, zig_##SmallType, trunc, BigType, zig_##BigType, 2) \ + zig_convert_float(BigType, zig_##BigType, extend, SmallType, zig_##SmallType, 2) +zig_convert_floats(f16, f32) +zig_convert_floats(f16, f64) +zig_convert_floats(f16, f80) +zig_convert_floats(f16, f128) +zig_convert_floats(f32, f64) +zig_convert_floats(f32, f80) +zig_convert_floats(f32, f128) +zig_convert_floats(f64, f80) +zig_convert_floats(f64, f128) +zig_convert_floats(f80, f128) -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_d2f(zig_f64); -static inline zig_f32 zig_truncdfsf(zig_f64 arg) { return __aeabi_d2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_f2d(zig_f32); -static inline zig_f64 zig_extendsfdf(zig_f32 arg) { return __aeabi_f2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2) - -#endif /* __ARM_EABI__ */ - -#define zig_float_negate_builtin_0(w, c, sb) \ - zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb)) -#define zig_float_negate_builtin_1(w, c, sb) -arg -#define zig_float_negate_builtin(w, c, sb) \ +#define zig_float_negate_builtin_0(w, sb) \ + zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, sb)) +#define zig_float_negate_builtin_1(w, sb) -arg +#define zig_float_negate_builtin(w, sb) \ static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \ - return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \ + return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, sb); \ } -zig_float_negate_builtin(16, , UINT16_C(1) << 15 ) -zig_float_negate_builtin(32, , UINT32_C(1) << 31 ) -zig_float_negate_builtin(64, , UINT64_C(1) << 63 ) -zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0))) -zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) +zig_float_negate_builtin(16, UINT16_C(1) << 15) +zig_float_negate_builtin(32, UINT32_C(1) << 31) +zig_float_negate_builtin(64, UINT64_C(1) << 63) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_mantissa_repr_f##w(arg), zig_xor_u16(zig_exponent_repr_f##w(arg), sb)) +zig_float_negate_builtin(80, UINT16_C(1) << 15) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_xor_u64(zig_hi_repr_f##w(arg), sb), zig_lo_repr_f##w(arg)) +zig_float_negate_builtin(128, UINT64_C(1) << 63) #define zig_float_less_builtin_0(Type, operation) \ - zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \ + zig_extern zig_FloatCompareResult zig_expand_concat(zig_expand_concat(__##operation, \ zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ + return (int32_t)zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ } #define zig_float_less_builtin_1(Type, operation) \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ @@ -3994,13 +6077,52 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) return lhs operator rhs; \ } +#define zig_float_builtins(w) \ + zig_common_float_builtins(w) \ + zig_convert_float(f##w, zig_f##w, float, int128, zig_i128, ) \ + zig_convert_float(f##w, zig_f##w, floatun, int128, zig_u128, ) #define zig_common_float_builtins(w) \ - zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \ + zig_convert_float(always, int32_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, int64_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_i128, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, uint32_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(always, uint64_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_u128, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int32_t, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int64_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint32_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint64_t, ) \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatunei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \ @@ -4031,82 +6153,48 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_max_f##w, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_fma_f##w, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ \ - static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divTrunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_trunc_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divFloor_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divCeil_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ + return zig_sub_f##w(lhs, zig_mul_f##w(zig_divFloor_f##w(lhs, rhs), rhs)); \ } -zig_common_float_builtins(16) -zig_common_float_builtins(32) -zig_common_float_builtins(64) -zig_common_float_builtins(80) -zig_common_float_builtins(128) - -#define zig_float_builtins(w) \ - zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) zig_float_builtins(16) -zig_float_builtins(80) -zig_float_builtins(128) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_f2iz(zig_f32); -static inline int32_t zig_fixsfsi(zig_f32 arg) { return __aeabi_f2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_f2uiz(zig_f32); -static inline uint32_t zig_fixunssfsi(zig_f32 arg) { return __aeabi_f2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_f2ulz(zig_f32); -static inline uint64_t zig_fixunssfdi(zig_f32 arg) { return __aeabi_f2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_i2f(int32_t); -static inline zig_f32 zig_floatsisf(int32_t arg) { return __aeabi_i2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ui2f(uint32_t); -static inline zig_f32 zig_floatunsisf(uint32_t arg) { return __aeabi_ui2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ul2f(uint64_t); -static inline zig_f32 zig_floatundisf(uint64_t arg) { return __aeabi_ul2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_d2iz(zig_f64); -static inline int32_t zig_fixdfsi(zig_f64 arg) { return __aeabi_d2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_d2uiz(zig_f64); -static inline uint32_t zig_fixunsdfsi(zig_f64 arg) { return __aeabi_d2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_d2ulz(zig_f64); -static inline uint64_t zig_fixunsdfdi(zig_f64 arg) { return __aeabi_d2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_i2d(int32_t); -static inline zig_f64 zig_floatsidf(int32_t arg) { return __aeabi_i2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ui2d(uint32_t); -static inline zig_f64 zig_floatunsidf(uint32_t arg) { return __aeabi_ui2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ul2d(uint64_t); -static inline zig_f64 zig_floatundidf(uint64_t arg) { return __aeabi_ul2d(arg); } - -#else /* __ARM_EABI__ */ - zig_float_builtins(32) zig_float_builtins(64) - -#endif /* __ARM_EABI__ */ +zig_float_builtins(80) +#if defined(zig_x86_32) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_f128 arg); + return __floattitf(zig_f128_bitCast_i128(arg)); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(zig_f128 arg); + return __floatuntitf(zig_f128_bitCast_u128(arg)); +} +#elif defined(zig_x86_64) && defined(zig_windows) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_i128 arg); + return __floattitf(arg); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(uint64_t arg_lo, uint64_t arg_hi); + return __floatuntitf(zig_lo_u128(arg), zig_hi_u128(arg)); +} +#else +zig_float_builtins(128) +#endif /* ============================ Atomics Support ============================= */ @@ -4410,19 +6498,19 @@ typedef int zig_memory_order; } \ static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ (void)_InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ + } \ static inline Type zig_msvc_atomic_load_zig_memory_order_relaxed_##ZigType(Type volatile* obj) { \ return __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_acquire_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } zig_msvc_atomics( u8, uint8_t, char, 8, 8) @@ -4465,14 +6553,14 @@ zig_msvc_atomics(i64, int64_t, __int64, 64, 64) zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } \ static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##Type(zig_##Type volatile* obj) { \ zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } @@ -4502,9 +6590,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p32(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p32(void volatile* obj) { - void* val = (void*)__iso_volatile_load32(obj); + void* value = (void*)__iso_volatile_load32(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p32(void volatile* obj) { @@ -4532,9 +6620,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p64(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p64(void volatile* obj) { - void* val = (void*)__iso_volatile_load64(obj); + void* value = (void*)__iso_volatile_load64(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p64(void volatile* obj) { diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 1664bd4095df86103a6e4bacfc682054a0cb8fc1..8587696fd79e5f385e8ea9fcf56614213bcce485 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig index 895f9bbf8d956e61bdf5455084cd4d58ebd2b1e9..9c140d35499fe43c6dfb1b5309e4dbd8bd7263c0 100644 --- a/test/behavior/abs.zig +++ b/test/behavior/abs.zig @@ -144,7 +144,6 @@ test "@abs big int <= 128 bits" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try comptime testAbsSignedBigInt(); try testAbsSignedBigInt(); @@ -256,7 +255,6 @@ fn testAbsFloats(comptime T: type) !void { test "@abs int vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 9ffb238dfdb9994bf587b7e4e4b5743842dbcc4c..c9294e953b8d2c907a8b86e2c6b5916b1d75941a 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -129,8 +129,7 @@ test "alignment and size of structs with 128-bit fields" { y: u8, }; const expected = switch (builtin.cpu.arch) { - .s390x, - => .{ + .s390x => .{ .a_align = 8, .a_size = 16, @@ -142,7 +141,32 @@ test "alignment and size of structs with 128-bit fields" { .u129_align = 8, .u129_size = 24, }, + .x86 => switch (builtin.os.tag) { + else => .{ + .a_align = 4, + .a_size = 16, + .b_align = 4, + .b_size = 20, + + .u128_align = 4, + .u128_size = 16, + .u129_align = 4, + .u129_size = 20, + }, + .uefi, .windows => .{ + .a_align = 8, + .a_size = 16, + + .b_align = 8, + .b_size = 24, + + .u128_align = 8, + .u128_size = 16, + .u129_align = 8, + .u129_size = 24, + }, + }, .amdgcn, .arm, .armeb, @@ -155,12 +179,13 @@ test "alignment and size of structs with 128-bit fields" { .powerpc, .powerpcle, .riscv32, + .sparc, => .{ .a_align = 8, .a_size = 16, - .b_align = 16, - .b_size = 32, + .b_align = 8, + .b_size = 24, .u128_align = 8, .u128_size = 16, @@ -178,12 +203,10 @@ test "alignment and size of structs with 128-bit fields" { .nvptx64, .powerpc64, .powerpc64le, - .sparc, .sparc64, .riscv64, .wasm32, .wasm64, - .x86, .x86_64, => .{ .a_align = 16, @@ -200,12 +223,11 @@ test "alignment and size of structs with 128-bit fields" { else => return error.SkipZigTest, }; - const min_struct_align = if (builtin.zig_backend == .stage2_c) if (builtin.cpu.arch == .s390x) 8 else 16 else 0; comptime { - assert(@alignOf(A) == @max(expected.a_align, min_struct_align)); + assert(@alignOf(A) == expected.a_align); assert(@sizeOf(A) == expected.a_size); - assert(@alignOf(B) == @max(expected.b_align, min_struct_align)); + assert(@alignOf(B) == expected.b_align); assert(@sizeOf(B) == expected.b_size); assert(@alignOf(u128) == expected.u128_align); @@ -547,8 +569,6 @@ test "sub-aligned pointer field access" { } test "alignment of zero-bit types is respected" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO @@ -582,7 +602,6 @@ test "zero-bit fields in extern struct pad fields appropriately" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = extern struct { x: u8, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 16fdfc8c15cbd9f5e9ad3cc11d72461092cf839c..d1acfb366dbfe0620409a81ef565b0902237a81b 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -800,7 +800,6 @@ test "extern variable with non-pointer opaque type" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO @export(&var_to_export, .{ .name = "opaque_extern_var" }); @@ -1398,7 +1397,6 @@ test "allocation and looping over 3-byte integer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag.isDarwin()) return error.SkipZigTest; // TODO try expect(@sizeOf(u24) == 4); try expect(@sizeOf([1]u24) == 4); diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig index 9eed252ac8ddc055038a0bf227616f3df49369bd..a9d81b6b53e6d1761e99234200fdcc155e2efa1f 100644 --- a/test/behavior/bit_shifting.zig +++ b/test/behavior/bit_shifting.zig @@ -147,7 +147,6 @@ test "Saturating Shift Left where lhs is of a computed type" { test "Saturating Shift Left" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index b3b64af19b9d99ed922ec087209d02ecab14354a..785daa0d3194b00d43c00760a11199075d9377dd 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -210,7 +210,6 @@ test "triple level result location with bitcast sandwich passed as tuple element test "@bitCast packed struct of floats" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -247,7 +246,6 @@ test "@bitCast packed struct of floats" { test "comptime @bitCast packed struct to int and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -283,7 +281,6 @@ test "comptime @bitCast packed struct to int and back" { test "bitcast vector to integer and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -329,10 +326,10 @@ fn bitCastWrapper128(x: f128) u128 { } test "bitcast nan float does not modify signaling bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const snan_u16: u16 = 0x7D00; const snan_u32: u32 = 0x7FA00000; @@ -383,7 +380,6 @@ test "bitcast nan float does not modify signaling bit" { test "@bitCast of packed struct of bools all true" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO @@ -404,7 +400,6 @@ test "@bitCast of packed struct of bools all true" { test "@bitCast of packed struct of bools all false" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const P = packed struct { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index d13fc8e83d36590bb20b329f3accd39eae411a4d..077d3faeddc080357b48304a3f46240ad83e1fdd 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -134,7 +134,6 @@ test "@intFromFloat > 128 bits" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testIntFromFloat(f16, 1024, u140, 1024); try testIntFromFloat(f16, -1024, i140, -1024); @@ -160,7 +159,6 @@ test "@floatFromInt > 128 bits" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testFloatFromInt(u140, 1024, f16, 1024); try testFloatFromInt(i140, -1024, f16, -1024); @@ -182,8 +180,8 @@ test "@floatFromInt(f80)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; const S = struct { fn doTheTest(comptime Int: type) !void { @@ -207,7 +205,7 @@ test "@floatFromInt(f80)" { try S.doTheTest(i64); try S.doTheTest(i80); try S.doTheTest(i128); - // try S.doTheTest(i256); // TODO missing compiler_rt symbols + try S.doTheTest(i256); try comptime S.doTheTest(i31); try comptime S.doTheTest(i32); try comptime S.doTheTest(i45); @@ -281,6 +279,7 @@ test "type coercion from int to float" { test "@intFromFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + try testIntFromFloats(); try comptime testIntFromFloats(); } @@ -1473,11 +1472,6 @@ fn foobar(func: PFN_void) !void { test "cast function with an opaque parameter" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) { - // https://github.com/ziglang/zig/issues/16845 - return error.SkipZigTest; - } - const Container = struct { const Ctx = opaque {}; ctx: *Ctx, @@ -1724,9 +1718,7 @@ test "cast f16 to wider types" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1831,21 +1823,15 @@ test "pointer to empty struct literal to mutable slice" { test "coerce between pointers of compatible differently-named floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12396 - return error.SkipZigTest; - } - const F = switch (@typeInfo(c_longdouble).float.bits) { 64 => f64, 80 => f80, 128 => f128, - else => @compileError("unreachable"), + else => comptime unreachable, }; var f1: F = 12.34; const f2: *c_longdouble = &f1; diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 34adedf7267030379ee573cb519ce6dbe29c95e3..50a1b74d8ab76bdccf8b04795a04ca77bdee078b 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -168,7 +168,6 @@ test "@intCast <= 64 bits" { test "@intCast > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testIntCast(u8, 123, u140, 123); diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 60a06886d45ac988b55d0a51f5bc40101f098e7e..f86ab963d2a4ea5dd0cec5493f583ac672a174e7 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -513,7 +513,6 @@ test "runtime 128 bit integer division" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u128 = 152313999999999991610955792383; diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig index 4de68589468790419a9e993fd68caf2f20e6eae9..ed95406aa889d361abbf87a79764eb23d62021ca 100644 --- a/test/behavior/extern.zig +++ b/test/behavior/extern.zig @@ -3,7 +3,6 @@ const std = @import("std"); const expect = std.testing.expect; test "anyopaque extern symbol" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 85250c54ad7d083be1a2f132b7fdc0a2785e10b2..8694f366a586cd4a756f7f1acb7862c656b04f02 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -586,7 +586,6 @@ test "@fieldParentPtr extern struct last zero-bit field" { } test "@fieldParentPtr unaligned packed struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -725,7 +724,6 @@ test "@fieldParentPtr unaligned packed struct" { } test "@fieldParentPtr aligned packed struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1897,7 +1895,6 @@ test "@fieldParentPtr packed union" { } test "@fieldParentPtr tagged union all zero-bit fields" { - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 76b21b6f15316a95c3ee6d98a759ff06e8c03715..583b6bf6aba3f0596a452e5f311bc1a388cd4691 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -118,7 +118,6 @@ fn testMul(comptime T: type) !void { test "cmp f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testCmp(f16); try comptime testCmp(f16); @@ -127,7 +126,6 @@ test "cmp f16" { test "cmp f32" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testCmp(f32); try comptime testCmp(f32); @@ -142,7 +140,6 @@ test "cmp f64" { test "cmp f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -152,7 +149,6 @@ test "cmp f128" { test "cmp f80/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -220,7 +216,6 @@ test "vector cmp f16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; try testCmpVector(f16); @@ -253,7 +248,6 @@ test "vector cmp f64" { test "vector cmp f128" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest; @@ -381,11 +375,7 @@ test "@sqrt f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - - if (builtin.os.tag == .freebsd) { - // TODO https://github.com/ziglang/zig/issues/10875 - return error.SkipZigTest; - } + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; try testSqrt(f80); try comptime testSqrt(f80); @@ -431,9 +421,9 @@ fn testSqrt(comptime T: type) !void { var inf: T = math.inf(T); try expect(math.isPositiveInf(@sqrt(inf))); var zero: T = 0.0; - try expect(@sqrt(zero) == 0.0); + try expect(math.isPositiveZero(@sqrt(zero))); var neg_zero: T = -0.0; - try expect(@sqrt(neg_zero) == 0.0); + try expect(math.isNegativeZero(@sqrt(neg_zero))); var neg_one: T = -1.0; try expect(math.isNan(@sqrt(neg_one))); var nan: T = math.nan(T); @@ -947,7 +937,7 @@ test "@log2 with vectors" { builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) return error.SkipZigTest; - if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) { + if (builtin.os.tag == .windows and builtin.cpu.arch == .x86 and builtin.abi == .msvc) { // https://codeberg.org/ziglang/zig/issues/35518 return error.SkipZigTest; } @@ -1054,7 +1044,6 @@ test "@abs f32/f64" { test "@abs f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1172,16 +1161,10 @@ test "@floor f32/f64" { test "@floor f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testFloor(f80); try comptime testFloor(f80); try testFloor(f128); @@ -1261,16 +1244,10 @@ test "@ceil f32/f64" { test "@ceil f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testCeil(f80); try comptime testCeil(f80); try testCeil(f128); @@ -1281,16 +1258,10 @@ test "@ceil f80/f128/c_longdouble" { test "@ceil f80 maxInt(u64)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - var x: u64 = std.math.maxInt(u64); x = x; const float: f80 = @floatFromInt(x); @@ -1368,16 +1339,10 @@ test "@trunc f32/f64" { test "@trunc f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testTrunc(f80); try comptime testTrunc(f80); try testTrunc(f128); @@ -1440,11 +1405,6 @@ test "neg f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.os.tag == .freebsd) { - // TODO file issue to track this failure - return error.SkipZigTest; - } - try testNeg(f16); try comptime testNeg(f16); } @@ -1501,9 +1461,9 @@ fn testNeg(comptime T: type) !void { // subnormals var zero: T = 0.0; - try expect(-zero == -0.0); + try expect(math.isNegativeZero(-zero)); var neg_zero: T = -0.0; - try expect(-neg_zero == 0.0); + try expect(math.isPositiveZero(-neg_zero)); var true_min: T = math.floatTrueMin(T); try expect(-true_min == -math.floatTrueMin(T)); var neg_true_min: T = -math.floatTrueMin(T); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 14cb20f5442a452695ccad2134bd4d0c306ab4b2..47e6be86bb715f90bae1eb08a9237af2f07c1515 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -147,7 +147,6 @@ fn fnWithUnreachable() noreturn { test "extern struct with stdcallcc fn pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .x86) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = extern struct { diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 22b91be640579e1e8fe460f4652f998c5c1b9b6d..e76ca9850f3ce2bc9ca356910e76407dfae07fb1 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -873,7 +873,6 @@ test "umax wrapped squaring" { test "128-bit multiplication" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { @@ -968,7 +967,6 @@ test "@addWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest; try testAddWithOverflow(u129, 4, 105, 109, 0); try testAddWithOverflow(u129, 1000, 100, 1100, 0); @@ -1136,7 +1134,6 @@ test "Multiply unwrap error * immediate" { test "@mulWithOverflow bitsize 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1163,7 +1160,6 @@ test "@mulWithOverflow bitsize 128 bits" { test "@mulWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMulWithOverflow(u140, 0, maxInt(u140), 0, 0); @@ -1193,7 +1189,6 @@ test "@mulWithOverflow > 128 bits" { test "@mulWithOverflow bitsize 256 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1298,7 +1293,6 @@ test "@subWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest; try testSubWithOverflow(u129, 4, 105, maxInt(u129) - 100, 1); try testSubWithOverflow(u129, 1000, 100, 900, 0); @@ -1389,7 +1383,6 @@ test "@shlWithOverflow > 64 bits" { test "@shlWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testShlWithOverflow(u140, 1 << 100, 20, 1 << 120, 0); @@ -1419,7 +1412,6 @@ fn testAnd(comptime T: type, a: T, b: T, expected: T) !void { test "and > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88); try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100); @@ -1448,7 +1440,6 @@ fn testOr(comptime T: type, a: T, b: T, expected: T) !void { test "or > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testOr(u140, 0, 1 << 139, 1 << 139); try testOr(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf); @@ -1477,7 +1468,6 @@ fn testXor(comptime T: type, a: T, b: T, expected: T) !void { test "xor > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testXor(u140, 0, maxInt(u140), maxInt(u140)); try testXor(u140, 1 << 139, 1 << 139, 0); @@ -1506,7 +1496,6 @@ fn testNot(comptime T: type, a: T, expected: T) !void { test "not > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testNot(u140, 0, maxInt(u140)); try testNot(u140, maxInt(u140), 0); @@ -1535,7 +1524,6 @@ fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void { test "shl > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testShl(u140, 1 << 5, 10, 1 << 15); try testShl(u140, 3, 138, (1 << 139) | (1 << 138)); @@ -1564,7 +1552,6 @@ fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void { test "shr > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testShr(u140, 1 << 139, 39, 1 << 100); try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1); @@ -1593,7 +1580,6 @@ fn testClz(comptime T: type, a: T, expected: u16) !void { test "@clz > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testClz(u140, 0, 140); @@ -1623,7 +1609,6 @@ fn testCtz(comptime T: type, a: T, expected: u16) !void { test "@ctz > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testCtz(u140, 0, 140); @@ -1653,7 +1638,6 @@ fn testPopCount(comptime T: type, a: T, expected: u16) !void { test "@popCount > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testPopCount(u140, 0, 0); @@ -1683,7 +1667,6 @@ fn testBitReverse(comptime T: type, a: T, expected: T) !void { test "@bitReverse > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testBitReverse(u140, 1 << 139, 1); @@ -1713,7 +1696,6 @@ fn testByteSwap(comptime T: type, a: T, expected: T) !void { test "@byteSwap > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testByteSwap(u144, 1 << 136, 1); @@ -1743,7 +1725,6 @@ fn testMax(comptime T: type, a: T, b: T, expected: T) !void { test "@max > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMax(u140, 0, maxInt(u140), maxInt(u140)); @@ -1773,7 +1754,6 @@ fn testMin(comptime T: type, a: T, b: T, expected: T) !void { test "@min > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMin(u140, 0, maxInt(u140), 0); @@ -1803,7 +1783,6 @@ fn testAbs(comptime T: type, a: T, expected: anytype) !void { test "@abs > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testAbs(u140, 0, 0); try testAbs(u140, 1 << 139, 1 << 139); @@ -1827,7 +1806,6 @@ fn testRem(comptime T: type, numerator: T, denominator: T, expected: T) !void { test "@rem > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testRem(u140, 0, maxInt(u140), 0); @@ -1855,7 +1833,6 @@ fn testMod(comptime T: type, numerator: T, denominator: T, expected: T) !void { test "@mod > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMod(u140, 0, maxInt(u140), 0); @@ -1883,7 +1860,6 @@ fn testDivFloor(comptime T: type, numerator: T, denominator: T, expected: T) !vo test "@divFloor > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivFloor(u140, 0, maxInt(u140), 0); @@ -1912,7 +1888,6 @@ fn testDivCeil(comptime T: type, numerator: T, denominator: T, expected: T) !voi test "@divCeil > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivCeil(u140, 0, maxInt(u140), 0); @@ -1941,7 +1916,6 @@ fn testDivTrunc(comptime T: type, numerator: T, denominator: T, expected: T) !vo test "@divTrunc > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivTrunc(u140, 0, maxInt(u140), 0); @@ -2166,14 +2140,8 @@ test "remainder division" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; try comptime remdiv(f16); @@ -2315,7 +2283,6 @@ test "@round f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f80, 12.0); @@ -2326,7 +2293,6 @@ test "@round f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f128, 12.0); @@ -2366,7 +2332,6 @@ test "NaN comparison" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testNanEqNan(f16); try testNanEqNan(f32); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 22db5a75502f8456ac0637ef134a137434d3da75..533f44869573a924e50a08b3806a03c4243fc7ee 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -115,7 +115,6 @@ test "@min/max for floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 086a325bd6246dd660641aec924c20339494f8a2..bde6459e849c14384d69fc57811f59b747a0f2de 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -49,7 +49,6 @@ test "@mulAdd f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd80(); @@ -68,7 +67,6 @@ test "@mulAdd f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd128(); @@ -169,7 +167,6 @@ test "vector f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector80(); @@ -194,7 +191,6 @@ test "vector f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector128(); diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 96585d056cdf4c13b1aff3610ad08088fc0bf61c..045c19767454b64d970fe6c7a46dafcb9b2a1ac4 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -404,7 +404,6 @@ test "nested packed struct field pointers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO const S2 = packed struct { base: u8, @@ -579,7 +578,6 @@ test "packed struct fields modification" { } test "nested packed struct field access test" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -733,7 +731,6 @@ test "nested packed struct at non-zero offset 2" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -1171,7 +1168,6 @@ test "packed struct equality" { test "packed struct equality ignores padding bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = packed struct { b: bool }; diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 9ac875fad4990e03554fc217fb38f42d0dfa6e62..807f4f5450d3fb372e18e2fc78f71fea9ce4d5bb 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -275,7 +275,7 @@ test "compare equality of optional and non-optional pointer" { } test "allowzero pointer and slice" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index c434f014f36e40f2cfea9fc0c2508320d09c74a4..c5fa221c124d4113a73db22ab33778e521a9c52a 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -144,7 +144,6 @@ test "saturating multiplication <= 32 bits" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSatMul(u8, 0, maxInt(u8), 0); @@ -238,7 +237,6 @@ test "saturating multiplication" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -313,7 +311,6 @@ test "saturating shift-left" { test "saturating shift-left large rhs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; @@ -361,7 +358,6 @@ test "saturating shl uses the LHS type" { test "sat add > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatAdd(u140, 0, 0, 0); @@ -377,7 +373,6 @@ test "sat add > 128 bits" { test "sat sub > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatSub(u140, 0, 1, 0); @@ -393,7 +388,6 @@ test "sat sub > 128 bits" { test "sat mul > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatMul(u140, 0, maxInt(u140), 0); @@ -409,7 +403,6 @@ test "sat mul > 128 bits" { test "sat shl > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatShl(u140, 0, u8, 17, 0); diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 379e5ec18343c226b0e2d67b1dca8b8d53f13340..2aa7920ab4b17ae56df165a880d3242e3a3fedb0 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -535,7 +535,6 @@ test "zero-bit field in packed struct" { test "packed struct with non-ABI-aligned field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -792,7 +791,6 @@ test "non-packed struct with u128 entry in union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { @@ -1539,7 +1537,6 @@ test "instantiate struct with comptime field" { } test "struct field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1569,7 +1566,6 @@ test "struct field pointer has correct alignment" { } test "extern struct field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -2007,7 +2003,6 @@ test "initiate global variable with runtime value" { } test "struct containing optional pointer to array of @This()" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { @@ -2266,7 +2261,8 @@ test "struct contains aligned pointer to itself through type decl" { test "struct contains underaligned field with overaligned pointer to itself" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + const S = struct { ptr: *align(8) @This() align(1), }; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 6a44290f859261ad1c2f02974eb8525022fc0b25..c5ffdfa3e1872bfa58edb53b414b523660e9a9bb 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -1267,7 +1267,7 @@ test "switch with complex item expressions" { test "switch evaluation order" { const eu: anyerror!u32 = 0; _ = eu catch |err| switch (err) { - if (true) @compileError("unreachable") => unreachable, + if (true) comptime unreachable => unreachable, else => unreachable, }; } diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 9f4859789c9c3f23488ae0814c67b132112a3335..caaea13e7f8aa3571a0f3f34c7b05b0ee37eea3b 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -223,7 +223,6 @@ test "unanalyzed continue with operand" { test "switch loop on larger than pointer integer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var entry: @Int(.unsigned, @bitSizeOf(usize) + 1) = undefined; @@ -268,7 +267,7 @@ test "switch loop on non-exhaustive enum" { test "switch loop with discarded tag capture" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + const S = struct { const U = union(enum) { a: u32, diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig index c4353cd5df381e080489b9b5594df9d356277cc0..a57e93d0d1ca4bd502123b9e13ddcaeb7cbd9b68 100644 --- a/test/behavior/switch_on_captured_error.zig +++ b/test/behavior/switch_on_captured_error.zig @@ -243,7 +243,7 @@ test "switch on error union catch capture" { var a: error{}!u64 = 0; _ = &a; const b = a catch |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } @@ -829,7 +829,7 @@ test "switch on error union if else capture" { var a: error{}!u64 = 0; _ = &a; const b = if (a) |x| x else |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } @@ -840,7 +840,7 @@ test "switch on error union if else capture" { var a: error{}!u64 = 0; _ = &a; const b = if (a) |*x| x.* else |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index cb4480f759af537ee0824d400fda530eb21a69b7..ec1ce0b62677b9cbb4988814e4c69f94ae65548c 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -9,11 +9,6 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag.isDarwin()) { - // Fails due to register hazards. - return error.SkipZigTest; - } - const S = struct { threadlocal var t: i32 = 1234; }; diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index 07d19f29c0da73a045ae58d35836502cbebe5cdc..506a0d2bea99b768c6761cc3da31558b88eddf11 100644 --- a/test/behavior/truncate.zig +++ b/test/behavior/truncate.zig @@ -49,7 +49,6 @@ fn testTruncate(comptime S: type, a: S, comptime D: type, expected: D) !void { test "@truncate > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testTruncate(u140, 0, u128, 0); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 340f7006e72b7f48ecaf7280cd9cd982f8600060..0ba364aabe557a0bac5832d285cc4595dc9cec25 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1437,7 +1437,6 @@ test "coerce enum literal to union in result loc" { } test "defined-layout union field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1472,7 +1471,6 @@ test "defined-layout union field pointer has correct alignment" { } test "undefined-layout union field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1611,6 +1609,10 @@ fn littleToNativeEndian(comptime T: type, v: T) T { } test "reinterpret extern union" { + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isRiscv32() and builtin.link_libc) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest; + if (true) { // https://github.com/ziglang/zig/issues/19389 return error.SkipZigTest; @@ -1678,8 +1680,6 @@ test "reinterpret extern union" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO try S.doTheTest(); } @@ -1758,8 +1758,6 @@ test "reinterpret packed union" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try S.doTheTest(); } @@ -1800,8 +1798,6 @@ test "reinterpret packed union inside packed struct" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try S.doTheTest(); } diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 7d63b136fda14fca1358123c1546820a42f0dcf9..1b7d354e19c92996c8b6f30dde1acc2ad5914a4a 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -128,13 +128,6 @@ test "vector float operators" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; - - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { - // Triggers an assertion with LLVM 18: - // https://github.com/ziglang/zig/issues/20680 - return error.SkipZigTest; - } const S = struct { fn doTheTest(T: type) !void { @@ -280,7 +273,6 @@ test "array to vector with element type coercion" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -736,9 +728,7 @@ test "vector reduce operation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/195562 const S = struct { fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { @@ -776,6 +766,8 @@ test "vector reduce operation" { try testReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9)); try testReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9)); try testReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9)); + try testReduce(.Add, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 42.9)); + try testReduce(.Add, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 42.9)); try testReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false)); try testReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0)); @@ -794,6 +786,8 @@ test "vector reduce operation" { try testReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0)); try testReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0)); try testReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0)); + try testReduce(.Min, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, -100.0)); + try testReduce(.Min, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, -100.0)); try testReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4)); try testReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4)); @@ -806,6 +800,8 @@ test "vector reduce operation" { try testReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9)); try testReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9)); try testReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9)); + try testReduce(.Max, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, 10.0e9)); + try testReduce(.Max, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, 10.0e9)); try testReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24)); try testReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24)); @@ -818,6 +814,8 @@ test "vector reduce operation" { try testReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7)); try testReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7)); try testReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7)); + try testReduce(.Mul, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 58430.7)); + try testReduce(.Mul, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 58430.7)); try testReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true)); try testReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1)); @@ -825,6 +823,7 @@ test "vector reduce operation" { try testReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0)); try testReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff)); try testReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff)); + try testReduce(.Or, [4]u80{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u80, 0xffffffff)); try testReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true)); try testReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1)); @@ -837,22 +836,32 @@ test "vector reduce operation" { const f16_nan = math.nan(f16); const f32_nan = math.nan(f32); const f64_nan = math.nan(f64); + const f80_nan = math.nan(f80); + const f128_nan = math.nan(f128); try testReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); + try testReduce(.Add, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan); + try testReduce(.Add, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan); try testReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, -1.9)); try testReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, -1.9)); try testReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, -1.9)); + try testReduce(.Min, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, -1.9)); + try testReduce(.Min, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, -1.9)); try testReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, 100.0)); try testReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, 100.0)); try testReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, 100.0)); + try testReduce(.Max, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, 100.0)); + try testReduce(.Max, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, 100.0)); try testReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); + try testReduce(.Mul, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan); + try testReduce(.Mul, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan); } }; @@ -1321,11 +1330,6 @@ test "byte vector initialized in inline function" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and comptime builtin.cpu.has(.x86, .avx512f)) { - // TODO https://github.com/ziglang/zig/issues/13279 - return error.SkipZigTest; - } - const S = struct { fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) { return .{ e0, e1, e2, e3 }; @@ -1437,7 +1441,6 @@ test "store packed vector element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var v = @Vector(4, u1){ 1, 1, 1, 1 }; @@ -1469,7 +1472,6 @@ test "store vector with memset" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [5]@Vector(2, i1) = undefined; @@ -1610,7 +1612,6 @@ test "bitcast vector to array of smaller vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const u8x32 = @Vector(32, u8); const u8x64 = @Vector(64, u8); diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index c6571319d4fbb3a2265dd48fd31e67a9061e2055..6277c3acf6790cd769ac86dc885959e8281e7a71 100644 --- a/test/behavior/widening.zig +++ b/test/behavior/widening.zig @@ -41,7 +41,6 @@ test "float widening" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; var a: f16 = 12.34; var b: f32 = a; diff --git a/test/behavior/x86_64/unary.zig b/test/behavior/x86_64/unary.zig index 2b2a9e288b30c1c0a1d0ab1de61b23522582b6e8..263505f090d09aa3b76eddb309b0d6bd531057dc 100644 --- a/test/behavior/x86_64/unary.zig +++ b/test/behavior/x86_64/unary.zig @@ -56,7 +56,7 @@ fn unary(comptime op: anytype, comptime opts: struct { f32 => libc_name ++ "f", f64 => libc_name, f80 => "__" ++ libc_name ++ "x", - f128 => libc_name ++ "q", + f128 => libc_name ++ "f128", else => break :libc, }, .library_name = switch (@import("builtin").object_format) { diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index cfd3872c94ef750e6663f6e9c4d186516c76beb7..a1471283bfbc5ce35b9bdd4edd6e6cb6df81d831 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -77,7 +77,7 @@ static void assert_or_panic(bool ok) { # define ZIG_NO_COMPLEX #endif -#ifdef ZIG_PPC32 +#ifdef __powerpc__ # define ZIG_NO_COMPLEX #endif @@ -408,7 +408,11 @@ void c_test_longdouble(void) { zig_8_longdouble(0, 1, 2, 3, 4, 5, 6, 7, 10, 9); } -#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) || defined(__wasm__) +#ifndef __hexagon__ +#ifndef __loongarch__ +#ifndef __mips__ +#ifndef ZIG_PPC64 +#if !(defined(__i386__) && defined(_WIN32)) typedef bool Vector_2_bool __attribute__((ext_vector_type(2))); @@ -4657,6 +4661,10 @@ void c_test_vector_512_bool(void) { }); } +#endif +#endif +#endif +#endif #endif typedef uint8_t Vector_1_u8 __attribute__((vector_size(1 * sizeof(uint8_t)))); @@ -15186,6 +15194,126 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { zig_struct_f32_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32_f32){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_array_1_f32 { + float a[1]; +}; + +struct Struct_array_1_f32 zig_ret_struct_array_1_f32(void); +void zig_struct_array_1_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_1_f32(void) { + return (struct Struct_array_1_f32){ .a = { 4 } }; +} +void c_struct_array_1_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_1_f32(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f32((struct Struct_array_1_f32){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f32 { + float a[2]; +}; + +struct Struct_array_2_f32 zig_ret_struct_array_2_f32(void); +void zig_struct_array_2_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_2_f32(void) { + return (struct Struct_array_2_f32){ .a = { 6, 7 } }; +} +void c_struct_array_2_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_2_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f32((struct Struct_array_2_f32){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f32 { + float a[3]; +}; + +struct Struct_array_3_f32 zig_ret_struct_array_3_f32(void); +void zig_struct_array_3_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_3_f32(void) { + return (struct Struct_array_3_f32){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_3_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f32((struct Struct_array_3_f32){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f32 { + float a[4]; +}; + +struct Struct_array_4_f32 zig_ret_struct_array_4_f32(void); +void zig_struct_array_4_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_4_f32(void) { + return (struct Struct_array_4_f32){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f32(struct Struct_array_4_f32 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_4_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f32((struct Struct_array_4_f32){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f32 { + float a[5]; +}; + +struct Struct_array_5_f32 zig_ret_struct_array_5_f32(void); +void zig_struct_array_5_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_5_f32(void) { + return (struct Struct_array_5_f32){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f32(struct Struct_array_5_f32 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_5_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + struct Struct_f32a8 { alignas(8) float a; }; @@ -15401,6 +15529,126 @@ void c_test_struct_f64_f64_f64_f64_f64(void) { zig_struct_f64_f64_f64_f64_f64((struct Struct_f64_f64_f64_f64_f64){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_array_1_f64 { + double a[1]; +}; + +struct Struct_array_1_f64 zig_ret_struct_array_1_f64(void); +void zig_struct_array_1_f64(struct Struct_array_1_f64, size_t); + +struct Struct_array_1_f64 c_ret_struct_array_1_f64(void) { + return (struct Struct_array_1_f64){ .a = { 4 } }; +} +void c_struct_array_1_f64(struct Struct_array_1_f64 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f64(void) { + struct Struct_array_1_f64 s = zig_ret_struct_array_1_f64(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f64((struct Struct_array_1_f64){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f64 { + double a[2]; +}; + +struct Struct_array_2_f64 zig_ret_struct_array_2_f64(void); +void zig_struct_array_2_f64(struct Struct_array_2_f64, size_t); + +struct Struct_array_2_f64 c_ret_struct_array_2_f64(void) { + return (struct Struct_array_2_f64){ .a = { 6, 7 } }; +} +void c_struct_array_2_f64(struct Struct_array_2_f64 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f64(void) { + struct Struct_array_2_f64 s = zig_ret_struct_array_2_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f64((struct Struct_array_2_f64){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f64 { + double a[3]; +}; + +struct Struct_array_3_f64 zig_ret_struct_array_3_f64(void); +void zig_struct_array_3_f64(struct Struct_array_3_f64, size_t); + +struct Struct_array_3_f64 c_ret_struct_array_3_f64(void) { + return (struct Struct_array_3_f64){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f64(struct Struct_array_3_f64 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f64(void) { + struct Struct_array_3_f64 s = zig_ret_struct_array_3_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f64((struct Struct_array_3_f64){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f64 { + double a[4]; +}; + +struct Struct_array_4_f64 zig_ret_struct_array_4_f64(void); +void zig_struct_array_4_f64(struct Struct_array_4_f64, size_t); + +struct Struct_array_4_f64 c_ret_struct_array_4_f64(void) { + return (struct Struct_array_4_f64){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f64(struct Struct_array_4_f64 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f64(void) { + struct Struct_array_4_f64 s = zig_ret_struct_array_4_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f64((struct Struct_array_4_f64){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f64 { + double a[5]; +}; + +struct Struct_array_5_f64 zig_ret_struct_array_5_f64(void); +void zig_struct_array_5_f64(struct Struct_array_5_f64, size_t); + +struct Struct_array_5_f64 c_ret_struct_array_5_f64(void) { + return (struct Struct_array_5_f64){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f64(struct Struct_array_5_f64 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f64(void) { + struct Struct_array_5_f64 s = zig_ret_struct_array_5_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f64((struct Struct_array_5_f64){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + struct Struct_u32_Union_u32_u32u32 { uint32_t a; union { @@ -15563,8 +15811,7 @@ void run_c_tests(void) { #if !(defined(__i386__) && defined(_WIN32)) #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct Struct_i32_i32 s = {1, 2}; zig_struct_i32_i32(s); @@ -15573,13 +15820,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct BigStruct s = {1, 2, 3, 4, 5}; zig_big_struct(s); @@ -15588,7 +15833,6 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef ZIG_NO_I128 { @@ -15612,8 +15856,7 @@ void run_c_tests(void) { #ifndef __i386__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct SplitStructInts s = {1234, 100, 1337}; zig_split_struct_ints(s); @@ -15623,13 +15866,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct MedStructMixed s = {1234, 100.0f, 1337.0f}; zig_med_struct_mixed(s); @@ -15638,14 +15879,12 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __i386__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct SplitStructMixed s = {1234, 100, 1337.0f}; zig_split_struct_mixed(s); @@ -15655,13 +15894,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct BigStruct s = {30, 31, 32, 33, 34}; struct BigStruct res = zig_big_struct_both(s); @@ -15674,7 +15911,6 @@ void run_c_tests(void) { #endif #endif #endif -#endif #endif { diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 974adf898c9fd092396d279bf34a22f050235d73..16b99134cf70bc44a77179f48c68704d7a9041ec 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -13,7 +13,7 @@ const expectEqual = std.testing.expectEqual; const have_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPowerPC32() and builtin.cpu.arch != .riscv32 and builtin.cpu.arch != .hexagon and - builtin.cpu.arch != .s390x; // https://github.com/llvm/llvm-project/issues/168460 + builtin.cpu.arch != .s390x; const have_f128 = builtin.cpu.arch.isWasm() or (builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin() and builtin.abi != .msvc); const have_f80 = builtin.cpu.arch.isX86() and builtin.abi != .msvc; @@ -161,7 +161,7 @@ extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat; extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble; const complex_abi_compatible = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isMIPS() and - !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isPowerPC32() and !builtin.cpu.arch.isRISCV() and + !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isPowerPC() and !builtin.cpu.arch.isRISCV() and builtin.cpu.arch != .hexagon and builtin.cpu.arch != .s390x and !(builtin.cpu.arch.isLoongArch() and builtin.abi.float() == .soft); @@ -451,8 +451,11 @@ test "long double" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_2_bool() @Vector(2, bool) { @@ -474,7 +477,13 @@ extern fn c_vector_2_bool(@Vector(2, bool)) void; extern fn c_test_vector_2_bool() void; test "@Vector(2, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_2_bool(); try expect(vec[0] == true); @@ -488,8 +497,11 @@ test "@Vector(2, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_4_bool() @Vector(4, bool) { @@ -515,7 +527,13 @@ extern fn c_vector_4_bool(@Vector(4, bool)) void; extern fn c_test_vector_4_bool() void; test "@Vector(4, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_4_bool(); try expect(vec[0] == true); @@ -533,8 +551,11 @@ test "@Vector(4, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_8_bool() @Vector(8, bool) { @@ -568,7 +589,13 @@ extern fn c_vector_8_bool(@Vector(8, bool)) void; extern fn c_test_vector_8_bool() void; test "@Vector(8, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_8_bool(); try expect(vec[0] == false); @@ -594,8 +621,11 @@ test "@Vector(8, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_16_bool() @Vector(16, bool) { @@ -645,7 +675,13 @@ extern fn c_vector_16_bool(@Vector(16, bool)) void; extern fn c_test_vector_16_bool() void; test "@Vector(16, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_16_bool(); try expect(vec[0] == true); @@ -687,8 +723,11 @@ test "@Vector(16, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_32_bool() @Vector(32, bool) { @@ -770,7 +809,13 @@ extern fn c_vector_32_bool(@Vector(32, bool)) void; extern fn c_test_vector_32_bool() void; test "@Vector(32, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_32_bool(); try expect(vec[0] == true); @@ -844,8 +889,11 @@ test "@Vector(32, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_64_bool() @Vector(64, bool) { @@ -991,7 +1039,11 @@ extern fn c_vector_64_bool(@Vector(64, bool)) void; extern fn c_test_vector_64_bool() void; test "@Vector(64, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const vec = c_ret_vector_64_bool(); try expect(vec[0] == false); @@ -1129,8 +1181,11 @@ test "@Vector(64, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_128_bool() @Vector(128, bool) { @@ -1404,7 +1459,11 @@ extern fn c_vector_128_bool(@Vector(128, bool)) void; extern fn c_test_vector_128_bool() void; test "@Vector(128, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_128_bool(); try expect(vec[0] == false); @@ -1670,8 +1729,11 @@ test "@Vector(128, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_256_bool() @Vector(256, bool) { @@ -2201,7 +2263,11 @@ extern fn c_vector_256_bool(@Vector(256, bool)) void; extern fn c_test_vector_256_bool() void; test "@Vector(256, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_256_bool(); try expect(vec[0] == true); @@ -2723,8 +2789,11 @@ test "@Vector(256, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_512_bool() @Vector(512, bool) { @@ -3766,7 +3835,11 @@ extern fn c_vector_512_bool(@Vector(512, bool)) void; extern fn c_test_vector_512_bool() void; test "@Vector(512, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_512_bool(); try expect(vec[0] == false); @@ -4840,7 +4913,7 @@ test "@Vector(2, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_2_u8(); try expect(v[0] == 9); @@ -4869,7 +4942,6 @@ test "@Vector(3, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_3_u8(); try expect(v[0] == 19); @@ -4912,7 +4984,7 @@ test "@Vector(4, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_4_u8(); try expect(v[0] == 41); @@ -4946,7 +5018,6 @@ test "@Vector(6, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_6_u8(); try expect(v[0] == 53); @@ -5136,7 +5207,6 @@ test "@Vector(24, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u8(); try expect(v[0] == 57); @@ -5220,7 +5290,6 @@ test "@Vector(32, u8)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u8(); try expect(v[0] == 69); @@ -5330,7 +5399,6 @@ test "@Vector(48, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u8(); try expect(v[0] == 29); @@ -5473,7 +5541,6 @@ test "@Vector(64, u8)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u8(); try expect(v[0] == 53); @@ -5668,7 +5735,6 @@ test "@Vector(96, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u8(); try expect(v[0] == 82); @@ -5931,7 +5997,6 @@ test "@Vector(128, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u8(); try expect(v[0] == 30); @@ -6296,7 +6361,6 @@ test "@Vector(192, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_192_u8(); try expect(v[0] == 70); @@ -6797,7 +6861,6 @@ test "@Vector(256, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_256_u8(); try expect(v[0] == 66); @@ -7502,7 +7565,6 @@ test "@Vector(384, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_384_u8(); try expect(v[0] == 46); @@ -8479,7 +8541,6 @@ test "@Vector(512, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_512_u8(); try expect(v[0] == 38); @@ -9073,7 +9134,7 @@ test "@Vector(2, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_2_u16(); try expect(v[0] == 9); @@ -9101,7 +9162,6 @@ test "@Vector(3, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_3_u16(); try expect(v[0] == 19); @@ -9250,7 +9310,6 @@ test "@Vector(12, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_u16(); try expect(v[0] == 121); @@ -9300,7 +9359,6 @@ test "@Vector(16, u16)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u16(); try expect(v[0] == 177); @@ -9366,7 +9424,6 @@ test "@Vector(24, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u16(); try expect(v[0] == 257); @@ -9450,7 +9507,6 @@ test "@Vector(32, u16)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u16(); try expect(v[0] == 369); @@ -9560,7 +9616,6 @@ test "@Vector(48, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u16(); try expect(v[0] == 529); @@ -9704,7 +9759,6 @@ test "@Vector(64, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u16(); try expect(v[0] == 753); @@ -9899,7 +9953,6 @@ test "@Vector(96, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u16(); try expect(v[0] == 1082); @@ -10162,7 +10215,6 @@ test "@Vector(128, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u16(); try expect(v[0] == 1530); @@ -10527,7 +10579,6 @@ test "@Vector(192, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_192_u16(); try expect(v[0] == 2170); @@ -11028,7 +11079,6 @@ test "@Vector(256, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_256_u16(); try expect(v[0] == 3066); @@ -11445,7 +11495,6 @@ test "@Vector(6, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_u32(); try expect(v[0] == 53); @@ -11481,7 +11530,6 @@ test "@Vector(8, u32)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_u32(); try expect(v[0] == 81); @@ -11524,7 +11572,6 @@ test "@Vector(12, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_u32(); try expect(v[0] == 121); @@ -11574,7 +11621,6 @@ test "@Vector(16, u32)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u32(); try expect(v[0] == 177); @@ -11640,7 +11686,6 @@ test "@Vector(24, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u32(); try expect(v[0] == 257); @@ -11725,7 +11770,6 @@ test "@Vector(32, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u32(); try expect(v[0] == 369); @@ -11835,7 +11879,6 @@ test "@Vector(48, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u32(); try expect(v[0] == 529); @@ -11979,7 +12022,6 @@ test "@Vector(64, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u32(); try expect(v[0] == 753); @@ -12174,7 +12216,6 @@ test "@Vector(96, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u32(); try expect(v[0] == 1082); @@ -12437,7 +12478,6 @@ test "@Vector(128, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u32(); try expect(v[0] == 1530); @@ -12594,8 +12634,6 @@ extern fn c_vector_1_u64(@Vector(1, u64), usize) void; extern fn c_test_vector_1_u64() void; test "@Vector(1, u64)" { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; - const v = c_ret_vector_1_u64(); try expect(v[0] == 3); c_vector_1_u64(.{4}, 1); @@ -12644,7 +12682,6 @@ test "@Vector(3, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_3_u64(); try expect(v[0] == 19); @@ -12673,7 +12710,6 @@ test "@Vector(4, u64)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_4_u64(); try expect(v[0] == 33); @@ -12740,7 +12776,6 @@ test "@Vector(8, u64)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_u64(); try expect(v[0] == 81); @@ -12832,7 +12867,6 @@ test "@Vector(16, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u64(); try expect(v[0] == 177); @@ -12981,7 +13015,6 @@ test "@Vector(32, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u64(); try expect(v[0] == 369); @@ -13233,7 +13266,6 @@ test "@Vector(64, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u64(); try expect(v[0] == 753); @@ -13327,7 +13359,6 @@ test "@Vector(1, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_1_f32(); try expect(v[0] == 3); @@ -13449,7 +13480,6 @@ test "@Vector(6, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_f32(); try expect(v[0] == 53); @@ -13486,7 +13516,6 @@ test "@Vector(8, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_f32(); try expect(v[0] == 81); @@ -13529,7 +13558,6 @@ test "@Vector(12, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_f32(); try expect(v[0] == 121); @@ -13580,7 +13608,6 @@ test "@Vector(16, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_f32(); try expect(v[0] == 177); @@ -13646,7 +13673,6 @@ test "@Vector(24, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_f32(); try expect(v[0] == 257); @@ -13731,7 +13757,6 @@ test "@Vector(32, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_f32(); try expect(v[0] == 369); @@ -13841,7 +13866,6 @@ test "@Vector(48, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_f32(); try expect(v[0] == 529); @@ -13985,7 +14009,6 @@ test "@Vector(64, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_f32(); try expect(v[0] == 753); @@ -14180,7 +14203,6 @@ test "@Vector(96, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_f32(); try expect(v[0] == 1082); @@ -14443,7 +14465,6 @@ test "@Vector(128, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_f32(); try expect(v[0] == 1530); @@ -14651,7 +14672,6 @@ test "@Vector(3, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_3_f64(); try expect(v[0] == 19); @@ -14680,8 +14700,6 @@ test "@Vector(4, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899 const v = c_ret_vector_4_f64(); try expect(v[0] == 33); @@ -14714,7 +14732,6 @@ test "@Vector(6, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_f64(); try expect(v[0] == 53); @@ -14750,8 +14767,6 @@ test "@Vector(8, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899 const v = c_ret_vector_8_f64(); try expect(v[0] == 81); @@ -14794,7 +14809,6 @@ test "@Vector(12, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_f64(); try expect(v[0] == 121); @@ -14845,7 +14859,6 @@ test "@Vector(16, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_f64(); try expect(v[0] == 177); @@ -14911,7 +14924,6 @@ test "@Vector(24, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_f64(); try expect(v[0] == 257); @@ -14996,7 +15008,6 @@ test "@Vector(32, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_f64(); try expect(v[0] == 369); @@ -15106,7 +15117,6 @@ test "@Vector(48, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_f64(); try expect(v[0] == 529); @@ -15250,7 +15260,6 @@ test "@Vector(64, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_f64(); try expect(v[0] == 753); @@ -15345,7 +15354,6 @@ extern fn c_test_struct_u8() void; test "struct u8" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u8(); @@ -15376,8 +15384,7 @@ test "struct u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8(); @@ -15411,8 +15418,7 @@ test "struct u8, u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8_u8(); @@ -15449,8 +15455,7 @@ test "struct u8, u8, u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8_u8_u8(); @@ -15481,7 +15486,6 @@ extern fn c_test_struct_u16() void; test "struct u16" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u16(); @@ -15512,8 +15516,7 @@ test "struct u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16(); @@ -15547,9 +15550,8 @@ test "struct u16, u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16_u16(); @@ -15586,9 +15588,8 @@ test "struct u16, u16, u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16_u16_u16(); @@ -15619,7 +15620,6 @@ extern fn c_test_struct_u32() void; test "struct u32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u32(); @@ -15649,9 +15649,8 @@ extern fn c_test_struct_u32_u32() void; test "struct u32, u32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u32_u32(); @@ -15685,8 +15684,7 @@ test "struct u32, u32, u32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_u32_u32(); try expect(s.a == 8); @@ -15722,8 +15720,7 @@ test "struct u32, u32, u32, u32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_u32_u32_u32(); try expect(s.a == 10); @@ -15753,7 +15750,6 @@ extern fn c_test_struct_u64() void; test "struct u64" { if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u64(); @@ -15831,7 +15827,6 @@ extern fn c_test_struct_u64_u64() void; test "struct u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_u64_u64(); try expect(s.a == 21); @@ -15871,8 +15866,7 @@ extern fn c_test_struct_u64_u64_u64() void; test "struct u64, u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u64_u64_u64(); try expect(s.a == 8); @@ -15907,8 +15901,7 @@ extern fn c_test_struct_u64_u64_u64_u64() void; test "struct u64, u64, u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u64_u64_u64_u64(); try expect(s.a == 10); @@ -15937,8 +15930,7 @@ extern fn c_test_struct_f32() void; test "struct f32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f32(); @@ -15971,7 +15963,6 @@ test "struct f32, f32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f32_f32(); @@ -16007,7 +15998,6 @@ test "struct f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32(); try expect(s.a == 8); @@ -16045,7 +16035,6 @@ test "struct f32, f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32_f32(); try expect(s.a == 10); @@ -16085,7 +16074,6 @@ test "struct f32, f32, f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32_f32_f32(); try expect(s.a == 12); @@ -16097,6 +16085,181 @@ test "struct f32, f32, f32, f32, f32" { c_test_struct_f32_f32_f32_f32_f32(); } +const Struct_array_1_f32 = extern struct { + a: [1]f32, +}; + +comptime { + skip: { + if (builtin.cpu.arch.isWasm()) break :skip; + + _ = struct { + export fn zig_ret_struct_array_1_f32() Struct_array_1_f32 { + return .{ .a = .{1} }; + } + export fn zig_struct_array_1_f32(s: Struct_array_1_f32, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); + } + }; + } +} + +extern fn c_ret_struct_array_1_f32() Struct_array_1_f32; +extern fn c_struct_array_1_f32(Struct_array_1_f32, usize) void; +extern fn c_test_struct_array_1_f32() void; + +test "struct [1]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f32(); + try expect(s.a[0] == 4); + c_struct_array_1_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_f32(); +} + +const Struct_array_2_f32 = extern struct { + a: [2]f32, +}; + +export fn zig_ret_struct_array_2_f32() Struct_array_2_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f32(s: Struct_array_2_f32, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f32() Struct_array_2_f32; +extern fn c_struct_array_2_f32(Struct_array_2_f32, usize) void; +extern fn c_test_struct_array_2_f32() void; + +test "struct [2]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f32(); +} + +const Struct_array_3_f32 = extern struct { + a: [3]f32, +}; + +export fn zig_ret_struct_array_3_f32() Struct_array_3_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f32(s: Struct_array_3_f32, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f32() Struct_array_3_f32; +extern fn c_struct_array_3_f32(Struct_array_3_f32, usize) void; +extern fn c_test_struct_array_3_f32() void; + +test "struct [3]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f32(); +} + +const Struct_array_4_f32 = extern struct { + a: [4]f32, +}; + +export fn zig_ret_struct_array_4_f32() Struct_array_4_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f32(s: Struct_array_4_f32, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f32() Struct_array_4_f32; +extern fn c_struct_array_4_f32(Struct_array_4_f32, usize) void; +extern fn c_test_struct_array_4_f32() void; + +test "struct [4]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f32(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f32(); +} + +const Struct_array_5_f32 = extern struct { + a: [5]f32, +}; + +export fn zig_ret_struct_array_5_f32() Struct_array_5_f32 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f32(s: Struct_array_5_f32, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f32() Struct_array_5_f32; +extern fn c_struct_array_5_f32(Struct_array_5_f32, usize) void; +extern fn c_test_struct_array_5_f32() void; + +test "struct [5]f32" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f32(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f32(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f32(); +} + const Struct_f32a8 = extern struct { a: f32 align(8), }; @@ -16120,7 +16283,6 @@ test "struct f32 align(8)" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_f32a8(); @@ -16154,7 +16316,6 @@ test "struct f32 align(8), f32 align(8)" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_f32a8_f32a8(); @@ -16187,8 +16348,7 @@ test "struct {f32, f32}, f32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f32f32_f32(); try expect(s.a.b == 1.0); @@ -16221,8 +16381,7 @@ test "struct f32, {f32, f32}" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f32_f32f32(); try expect(s.a == 1.0); @@ -16250,9 +16409,8 @@ extern fn c_test_struct_f64() void; test "struct f64" { if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f64(); @@ -16282,8 +16440,7 @@ extern fn c_test_struct_f64_f64() void; test "struct f64, f64" { if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64(); try expect(s.a == 6); @@ -16315,8 +16472,7 @@ extern fn c_test_struct_f64_f64_f64() void; test "struct f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64(); try expect(s.a == 8); @@ -16351,8 +16507,7 @@ extern fn c_test_struct_f64_f64_f64_f64() void; test "struct f64, f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64_f64(); try expect(s.a == 10); @@ -16390,8 +16545,7 @@ extern fn c_test_struct_f64_f64_f64_f64_f64() void; test "struct f64, f64, f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64_f64_f64(); try expect(s.a == 12); @@ -16403,6 +16557,181 @@ test "struct f64, f64, f64, f64, f64" { c_test_struct_f64_f64_f64_f64_f64(); } +const Struct_array_1_f64 = extern struct { + a: [1]f64, +}; + +comptime { + skip: { + if (builtin.cpu.arch.isWasm()) break :skip; + + _ = struct { + export fn zig_ret_struct_array_1_f64() Struct_array_1_f64 { + return .{ .a = .{1} }; + } + export fn zig_struct_array_1_f64(s: Struct_array_1_f64, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); + } + }; + } +} + +extern fn c_ret_struct_array_1_f64() Struct_array_1_f64; +extern fn c_struct_array_1_f64(Struct_array_1_f64, usize) void; +extern fn c_test_struct_array_1_f64() void; + +test "struct [1]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f64(); + try expect(s.a[0] == 4); + c_struct_array_1_f64(.{ .a = .{5} }, 6); + c_test_struct_array_1_f64(); +} + +const Struct_array_2_f64 = extern struct { + a: [2]f64, +}; + +export fn zig_ret_struct_array_2_f64() Struct_array_2_f64 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f64(s: Struct_array_2_f64, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f64() Struct_array_2_f64; +extern fn c_struct_array_2_f64(Struct_array_2_f64, usize) void; +extern fn c_test_struct_array_2_f64() void; + +test "struct [2]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f64(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f64(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f64(); +} + +const Struct_array_3_f64 = extern struct { + a: [3]f64, +}; + +export fn zig_ret_struct_array_3_f64() Struct_array_3_f64 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f64(s: Struct_array_3_f64, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f64() Struct_array_3_f64; +extern fn c_struct_array_3_f64(Struct_array_3_f64, usize) void; +extern fn c_test_struct_array_3_f64() void; + +test "struct [3]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f64(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f64(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f64(); +} + +const Struct_array_4_f64 = extern struct { + a: [4]f64, +}; + +export fn zig_ret_struct_array_4_f64() Struct_array_4_f64 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f64(s: Struct_array_4_f64, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f64() Struct_array_4_f64; +extern fn c_struct_array_4_f64(Struct_array_4_f64, usize) void; +extern fn c_test_struct_array_4_f64() void; + +test "struct [4]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f64(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f64(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f64(); +} + +const Struct_array_5_f64 = extern struct { + a: [5]f64, +}; + +export fn zig_ret_struct_array_5_f64() Struct_array_5_f64 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f64(s: Struct_array_5_f64, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f64() Struct_array_5_f64; +extern fn c_struct_array_5_f64(Struct_array_5_f64, usize) void; +extern fn c_test_struct_array_5_f64() void; + +test "struct [5]f64" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f64(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f64(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f64(); +} + const Struct_u32_Union_u32_u32u32 = extern struct { a: u32, b: extern union { @@ -16430,8 +16759,7 @@ test "struct{u32,union{u32,struct{u32,u32}}}" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_union_u32_u32u32(); try expect(s.a == 1); @@ -16449,11 +16777,10 @@ extern fn c_mut_struct_i32_i32(Struct_i32_i32) Struct_i32_i32; extern fn c_struct_i32_i32(Struct_i32_i32) void; test "struct i32 i32" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s: Struct_i32_i32 = .{ @@ -16483,11 +16810,10 @@ const BigStruct = extern struct { extern fn c_big_struct(BigStruct) void; test "big struct" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = BigStruct{ .a = 1, @@ -16513,10 +16839,9 @@ const BigUnion = extern union { extern fn c_big_union(BigUnion) void; test "big union" { - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const x = BigUnion{ .a = BigStruct{ @@ -16548,11 +16873,10 @@ extern fn c_med_struct_mixed(MedStructMixed) void; extern fn c_ret_med_struct_mixed() MedStructMixed; test "medium struct of ints and floats" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = MedStructMixed{ .a = 1234, @@ -16628,12 +16952,11 @@ const SplitStructInt = extern struct { extern fn c_split_struct_ints(SplitStructInt) void; test "split struct of ints" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = SplitStructInt{ .a = 1234, @@ -16658,12 +16981,11 @@ extern fn c_split_struct_mixed(SplitStructMixed) void; extern fn c_ret_split_struct_mixed() SplitStructMixed; test "split struct of ints and floats" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = SplitStructMixed{ .a = 1234, @@ -16686,11 +17008,10 @@ export fn zig_split_struct_mixed(x: SplitStructMixed) void { extern fn c_big_struct_both(BigStruct) BigStruct; test "sret and byval together" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = BigStruct{ .a = 1, @@ -16800,12 +17121,11 @@ extern fn c_struct_with_array(StructWithArray) void; extern fn c_ret_struct_with_array() StructWithArray; test "Struct with array as padding." { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 }); @@ -16829,11 +17149,10 @@ extern fn c_float_array_struct(FloatArrayStruct) void; extern fn c_ret_float_array_struct() FloatArrayStruct; test "Float array like struct" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; c_float_array_struct(.{ .origin = .{ @@ -16864,37 +17183,37 @@ pub inline fn expectOk(c_err: c_int) !void { /// Tests for Double + Char struct const DC = extern struct { v1: f64, v2: u8 }; test "DC: Zig passes to C" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 })); } test "DC: Zig returns to C" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_ret_DC()); } test "DC: C passes to Zig" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_send_DC()); } test "DC: C returns to Zig" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectEqual(DC{ .v1 = -0.25, .v2 = 15 }, c_ret_DC()); } @@ -16919,36 +17238,35 @@ const CFF = extern struct { v1: u8, v2: f32, v3: f32 }; test "CFF: Zig passes to C" { if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 })); } test "CFF: Zig returns to C" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_ret_CFF()); } test "CFF: C passes to Zig" { - if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; + if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; try expectOk(c_send_CFF()); } test "CFF: C returns to Zig" { - if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; + try expectEqual(CFF{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }, c_ret_CFF()); } pub extern fn c_assert_CFF(lv: CFF) c_int; @@ -16971,35 +17289,35 @@ pub export fn zig_ret_CFF() CFF { const PD = extern struct { v1: ?*anyopaque, v2: f64 }; test "PD: Zig passes to C" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 })); } test "PD: Zig returns to C" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + try expectOk(c_assert_ret_PD()); } test "PD: C passes to Zig" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + try expectOk(c_send_PD()); } test "PD: C returns to Zig" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + try expectEqual(PD{ .v1 = null, .v2 = 0.5 }, c_ret_PD()); } pub extern fn c_assert_PD(lv: PD) c_int; @@ -17033,7 +17351,6 @@ extern fn c_modify_by_ref_param(ByRef) ByRef; test "C function modifies by ref param" { if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); try expect(res.val == 42); @@ -17054,11 +17371,10 @@ const ByVal = extern struct { extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; test "C function that takes byval struct called via function pointer" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; var fn_ptr = &c_func_ptr_byval; _ = &fn_ptr; @@ -17077,17 +17393,16 @@ test "C function that takes byval struct called via function pointer" { extern fn c_f16(f16) f16; test "f16 bare" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; if (builtin.cpu.arch == .x86_64) return error.SkipZigTest; - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; - if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; const a = c_f16(12); try expect(a == 34); @@ -17098,9 +17413,9 @@ const f16_struct = extern struct { }; extern fn c_f16_struct(f16_struct) f16_struct; test "f16 struct" { + if (builtin.cpu.arch.isArm() and builtin.mode != .debug) return error.SkipZigTest; if (builtin.target.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.mode != .debug) return error.SkipZigTest; if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; @@ -17207,11 +17522,10 @@ const Coord2 = extern struct { extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2; test "Stdcall ABI structs" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const res = stdcall_coord2( @@ -17225,10 +17539,9 @@ test "Stdcall ABI structs" { extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void; test "Stdcall ABI big union" { - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const x = BigUnion{ .a = BigStruct{ @@ -17300,11 +17613,10 @@ const byval_tail_callsite_attr = struct { }; test "byval tail callsite attribute" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; // Originally reported at https://github.com/ziglang/zig/issues/16290 // the bug was that the extern function had the byval attribute, but diff --git a/test/standalone/build.zig b/test/standalone/build.zig index dc8d85d399477256b65c60dc1b4850144c641738..f14d17562d4715ca75340d67b6b2ce5b7344b73d 100644 --- a/test/standalone/build.zig +++ b/test/standalone/build.zig @@ -39,7 +39,6 @@ pub fn build(b: *std.Build) void { "../../tools/gen_parser_oracle.zig", "../../tools/gen_spirv_spec.zig", "../../tools/gen_stubs.zig", - "../../tools/generate_c_size_and_align_checks.zig", "../../tools/generate_JSONTestSuite.zig", "../../tools/generate_linux_syscalls.zig", "../../tools/process_headers.zig", diff --git a/test/tests.zig b/test/tests.zig index 9a11d7c496a5179e02c74969f4481034764baa55..d823d2add16c8a4486decb3671025cd60cbc16e2 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -274,6 +274,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabi, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .arm, @@ -292,6 +301,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabihf, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .arm, @@ -341,6 +359,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .armeb, + .os_tag = .linux, + .abi = .musleabi, + .ofmt = .c, + }, + .link_libc = true, + }, // Crashes in weird ways when applying relocations. // .{ // .target = .{ @@ -360,6 +387,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .armeb, + .os_tag = .linux, + .abi = .musleabihf, + .ofmt = .c, + }, + .link_libc = true, + }, // Crashes in weird ways when applying relocations. // .{ // .target = .{ @@ -1107,6 +1143,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .linux, + .abi = .musl, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .x86, @@ -1645,6 +1690,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .gnu, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ @@ -1961,7 +2015,6 @@ const c_abi_targets = blk: { .abi = .musl, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -1972,7 +2025,6 @@ const c_abi_targets = blk: { }, .use_llvm = false, .strip = true, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -1983,7 +2035,6 @@ const c_abi_targets = blk: { }, .use_llvm = false, .pic = true, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2028,7 +2079,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2038,7 +2088,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2048,7 +2097,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2782,16 +2830,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { const target = &resolved_target.result; - if (target.cpu.arch == .s390x and target.ofmt == .c) { - // https://codeberg.org/ziglang/zig/issues/35523 - continue; - } - - if (target.cpu.arch == .riscv64 and target.ofmt == .c) { - // https://codeberg.org/ziglang/zig/issues/30930 - continue; - } - if (std.mem.eql(u8, options.name, "libc")) { // The libc API tests obviously need to link libc. So for test // target entries where we wouldn't link libc by default, skip the diff --git a/tools/generate_c_size_and_align_checks.zig b/tools/generate_c_size_and_align_checks.zig deleted file mode 100644 index 09400615f2c526bdde3ce99c62b0f5a0bf386932..0000000000000000000000000000000000000000 --- a/tools/generate_c_size_and_align_checks.zig +++ /dev/null @@ -1,62 +0,0 @@ -//! Usage: zig run tools/generate_c_size_and_align_checks.zig -- [target_triple] -//! e.g. zig run tools/generate_c_size_and_align_checks.zig -- x86_64-linux-gnu -//! -//! Prints _Static_asserts for the size and alignment of all the basic built-in C -//! types. The output can be run through a compiler for the specified target to -//! verify that Zig's values are the same as those used by a C compiler for the -//! target. - -const std = @import("std"); -const Io = std.Io; - -fn cName(ty: std.Target.CType) []const u8 { - return switch (ty) { - .char => "char", - .short => "short", - .ushort => "unsigned short", - .int => "int", - .uint => "unsigned int", - .long => "long", - .ulong => "unsigned long", - .longlong => "long long", - .ulonglong => "unsigned long long", - .float => "float", - .double => "double", - .longdouble => "long double", - }; -} - -var general_purpose_allocator: std.heap.DebugAllocator(.{}) = .init; - -pub fn main(init: std.process.Init) !void { - const args = try init.minimal.args.toSlice(init.arena.allocator()); - const io = init.io; - - if (args.len != 2) { - std.debug.print("Usage: {s} [target_triple]\n", .{args[0]}); - std.process.exit(1); - } - - const query = try std.Target.Query.parse(.{ .arch_os_abi = args[1] }); - const target = try std.zig.system.resolveTargetQuery(io, query); - - var buffer: [2000]u8 = undefined; - var stdout_writer = Io.File.stdout().writerStreaming(io, &buffer); - const w = &stdout_writer.interface; - inline for (@typeInfo(std.Target.CType).@"enum".field_values) |field_value| { - const c_type: std.Target.CType = @fromBackingInt(@intCast(field_value)); - try w.print("_Static_assert(sizeof({0s}) == {1d}, \"sizeof({0s}) == {1d}\");\n", .{ - cName(c_type), - target.cTypeByteSize(c_type), - }); - try w.print("_Static_assert(_Alignof({0s}) == {1d}, \"_Alignof({0s}) == {1d}\");\n", .{ - cName(c_type), - target.cTypeAlignment(c_type), - }); - try w.print("_Static_assert(__alignof({0s}) == {1d}, \"__alignof({0s}) == {1d}\");\n\n", .{ - cName(c_type), - target.cTypePreferredAlignment(c_type), - }); - } - try w.flush(); -}