From 80790be3094f65877231209532c04f7fdb4441a7 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 10 Jun 2022 10:25:59 +0200 Subject: compiler_rt: compile each unit separately for improved archiving --- src/Compilation.zig | 27 ++++---- src/compiler_rt.zig | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/link/Coff.zig | 2 +- src/link/Elf.zig | 2 +- src/link/MachO.zig | 2 +- src/link/Wasm.zig | 2 +- src/musl.zig | 1 - 7 files changed, 206 insertions(+), 16 deletions(-) create mode 100644 src/compiler_rt.zig (limited to 'src') diff --git a/src/Compilation.zig b/src/Compilation.zig index 54d87faa7b..0cd40a7001 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -23,6 +23,7 @@ const mingw = @import("mingw.zig"); const libunwind = @import("libunwind.zig"); const libcxx = @import("libcxx.zig"); const wasi_libc = @import("wasi_libc.zig"); +const compiler_rt = @import("compiler_rt.zig"); const fatal = @import("main.zig").fatal; const clangMain = @import("main.zig").clangMain; const Module = @import("Module.zig"); @@ -131,7 +132,7 @@ libssp_static_lib: ?CRTFile = null, libc_static_lib: ?CRTFile = null, /// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). -compiler_rt_static_lib: ?CRTFile = null, +compiler_rt_static_lib: compiler_rt.CompilerRtLib = .{}, /// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). compiler_rt_obj: ?CRTFile = null, @@ -175,7 +176,7 @@ pub const CRTFile = struct { lock: Cache.Lock, full_object_path: []const u8, - fn deinit(self: *CRTFile, gpa: Allocator) void { + pub fn deinit(self: *CRTFile, gpa: Allocator) void { self.lock.release(); gpa.free(self.full_object_path); self.* = undefined; @@ -1978,9 +1979,7 @@ pub fn destroy(self: *Compilation) void { if (self.libcxxabi_static_lib) |*crt_file| { crt_file.deinit(gpa); } - if (self.compiler_rt_static_lib) |*crt_file| { - crt_file.deinit(gpa); - } + self.compiler_rt_static_lib.deinit(gpa); if (self.compiler_rt_obj) |*crt_file| { crt_file.deinit(gpa); } @@ -3138,11 +3137,9 @@ fn processOneJob(comp: *Compilation, job: Job) !void { const named_frame = tracy.namedFrame("compiler_rt_lib"); defer named_frame.end(); - comp.buildOutputFromZig( - "compiler_rt.zig", - .Lib, + compiler_rt.buildCompilerRtLib( + comp, &comp.compiler_rt_static_lib, - .compiler_rt, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already @@ -4897,7 +4894,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void { } } -fn buildOutputFromZig( +pub fn buildOutputFromZig( comp: *Compilation, src_basename: []const u8, output_mode: std.builtin.OutputMode, @@ -4914,7 +4911,15 @@ fn buildOutputFromZig( .root_src_path = src_basename, }; defer main_pkg.deinitTable(comp.gpa); - const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; + + const root_name = root_name: { + const basename = if (std.fs.path.dirname(src_basename)) |dirname| + src_basename[dirname.len + 1 ..] + else + src_basename; + const root_name = basename[0 .. basename.len - std.fs.path.extension(basename).len]; + break :root_name root_name; + }; const target = comp.getTarget(); const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{ .root_name = root_name, diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig new file mode 100644 index 0000000000..82b482daa8 --- /dev/null +++ b/src/compiler_rt.zig @@ -0,0 +1,186 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const Allocator = std.mem.Allocator; +const mem = std.mem; +const tracy = @import("tracy.zig"); +const trace = tracy.trace; + +const Compilation = @import("Compilation.zig"); +const CRTFile = Compilation.CRTFile; +const LinkObject = Compilation.LinkObject; +const Package = @import("Package.zig"); + +pub const CompilerRtLib = struct { + crt_object_files: [sources.len]?CRTFile = undefined, + crt_lib_file: ?CRTFile = null, + + pub fn deinit(crt_lib: *CompilerRtLib, gpa: Allocator) void { + for (crt_lib.crt_object_files) |*crt_file| { + if (crt_file.*) |*cf| { + cf.deinit(gpa); + } + } + if (crt_lib.crt_lib_file) |*crt_file| { + crt_file.deinit(gpa); + } + } +}; + +pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *CompilerRtLib) !void { + const tracy_trace = trace(@src()); + defer tracy_trace.end(); + + var progress: std.Progress = .{ .dont_print_on_dumb = true }; + var progress_node = progress.start("Compile Compiler-RT", sources.len + 1); + defer progress_node.end(); + if (comp.color == .off) progress.terminal = null; + + progress_node.activate(); + + var link_objects: [sources.len]LinkObject = undefined; + for (sources) |source, i| { + var obj_progress_node = progress_node.start(source, 0); + obj_progress_node.activate(); + defer obj_progress_node.end(); + + try comp.buildOutputFromZig(source, .Obj, &compiler_rt_lib.crt_object_files[i], .compiler_rt); + link_objects[i] = .{ + .path = compiler_rt_lib.crt_object_files[i].?.full_object_path, + .must_link = true, + }; + } + + const root_name = "compiler_rt"; + + var lib_progress_node = progress_node.start(root_name, 0); + lib_progress_node.activate(); + defer lib_progress_node.end(); + + const target = comp.getTarget(); + const basename = try std.zig.binNameAlloc(comp.gpa, .{ + .root_name = root_name, + .target = target, + .output_mode = .Lib, + }); + errdefer comp.gpa.free(basename); + + // TODO: This is extracted into a local variable to work around a stage1 miscompilation. + const emit_bin = Compilation.EmitLoc{ + .directory = null, // Put it in the cache directory. + .basename = basename, + }; + const sub_compilation = try Compilation.create(comp.gpa, .{ + .local_cache_directory = comp.global_cache_directory, + .global_cache_directory = comp.global_cache_directory, + .zig_lib_directory = comp.zig_lib_directory, + .cache_mode = .whole, + .target = target, + .root_name = root_name, + .main_pkg = null, + .output_mode = .Lib, + .link_mode = .Static, + .function_sections = true, + .thread_pool = comp.thread_pool, + .libc_installation = comp.bin_file.options.libc_installation, + .emit_bin = emit_bin, + .optimize_mode = comp.compilerRtOptMode(), + .want_sanitize_c = false, + .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, + .want_valgrind = false, + .want_tsan = false, + .want_pic = comp.bin_file.options.pic, + .want_pie = comp.bin_file.options.pie, + .want_lto = comp.bin_file.options.lto, + .emit_h = null, + .strip = comp.compilerRtStrip(), + .is_native_os = comp.bin_file.options.is_native_os, + .is_native_abi = comp.bin_file.options.is_native_abi, + .self_exe_path = comp.self_exe_path, + .link_objects = &link_objects, + .verbose_cc = comp.verbose_cc, + .verbose_link = comp.bin_file.options.verbose_link, + .verbose_air = comp.verbose_air, + .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_cimport = comp.verbose_cimport, + .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, + .clang_passthrough_mode = comp.clang_passthrough_mode, + .skip_linker_dependencies = true, + .parent_compilation_link_libc = comp.bin_file.options.link_libc, + }); + defer sub_compilation.destroy(); + + try sub_compilation.updateSubCompilation(); + + compiler_rt_lib.crt_lib_file = .{ + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.options.emit.?.sub_path, + }), + .lock = sub_compilation.bin_file.toOwnedLock(), + }; +} + +const sources = &[_][]const u8{ + "compiler_rt/atomics.zig", + "compiler_rt/sin.zig", + "compiler_rt/cos.zig", + "compiler_rt/sincos.zig", + "compiler_rt/ceil.zig", + "compiler_rt/exp.zig", + "compiler_rt/exp2.zig", + "compiler_rt/fabs.zig", + "compiler_rt/floor.zig", + "compiler_rt/fma.zig", + "compiler_rt/fmax.zig", + "compiler_rt/fmin.zig", + "compiler_rt/fmod.zig", + "compiler_rt/log.zig", + "compiler_rt/log10.zig", + "compiler_rt/log2.zig", + "compiler_rt/round.zig", + "compiler_rt/sqrt.zig", + "compiler_rt/tan.zig", + "compiler_rt/trunc.zig", + "compiler_rt/extendXfYf2.zig", + "compiler_rt/extend_f80.zig", + "compiler_rt/compareXf2.zig", + "compiler_rt/stack_probe.zig", + "compiler_rt/divti3.zig", + "compiler_rt/modti3.zig", + "compiler_rt/multi3.zig", + "compiler_rt/udivti3.zig", + "compiler_rt/udivmodti4.zig", + "compiler_rt/umodti3.zig", + "compiler_rt/truncXfYf2.zig", + "compiler_rt/trunc_f80.zig", + "compiler_rt/addXf3.zig", + "compiler_rt/mulXf3.zig", + "compiler_rt/divsf3.zig", + "compiler_rt/divdf3.zig", + "compiler_rt/divxf3.zig", + "compiler_rt/divtf3.zig", + "compiler_rt/floatXiYf.zig", + "compiler_rt/fixXfYi.zig", + "compiler_rt/count0bits.zig", + "compiler_rt/parity.zig", + "compiler_rt/popcount.zig", + "compiler_rt/bswap.zig", + "compiler_rt/int.zig", + "compiler_rt/shift.zig", + "compiler_rt/negXi2.zig", + "compiler_rt/muldi3.zig", + "compiler_rt/absv.zig", + "compiler_rt/negv.zig", + "compiler_rt/addo.zig", + "compiler_rt/subo.zig", + "compiler_rt/mulo.zig", + "compiler_rt/cmp.zig", + "compiler_rt/negXf2.zig", + "compiler_rt/os_version_check.zig", + "compiler_rt/emutls.zig", + "compiler_rt/arm.zig", + "compiler_rt/aulldiv.zig", + "compiler_rt/sparc.zig", + "compiler_rt/clear_cache.zig", +}; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 37ec8d0758..4ab7cee6e1 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1354,7 +1354,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! } // MSVC compiler_rt is missing some stuff, so we build it unconditionally but // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. - if (comp.compiler_rt_static_lib) |lib| { + if (comp.compiler_rt_static_lib.crt_lib_file) |lib| { try argv.append(lib.full_object_path); } } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e0f114acd4..046aa2ec0a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1272,7 +1272,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const stack_size = self.base.options.stack_size_override orelse 16777216; const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; const compiler_rt_path: ?[]const u8 = blk: { - if (comp.compiler_rt_static_lib) |x| break :blk x.full_object_path; + if (comp.compiler_rt_static_lib.crt_lib_file) |x| break :blk x.full_object_path; if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; break :blk null; }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index a4d14b985f..780b4b0483 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -738,7 +738,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try positionals.append(p); } - if (comp.compiler_rt_static_lib) |lib| { + if (comp.compiler_rt_static_lib.crt_lib_file) |lib| { try positionals.append(lib.full_object_path); } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ee2ed19ed5..30a1c49794 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2255,7 +2255,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const is_obj = self.base.options.output_mode == .Obj; const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj) - comp.compiler_rt_static_lib.?.full_object_path + comp.compiler_rt_static_lib.crt_lib_file.?.full_object_path else null; diff --git a/src/musl.zig b/src/musl.zig index d061addc9a..68b524b415 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -4,7 +4,6 @@ const mem = std.mem; const path = std.fs.path; const assert = std.debug.assert; -const target_util = @import("target.zig"); const Compilation = @import("Compilation.zig"); const build_options = @import("build_options"); -- cgit v1.2.3 From 2259d629d3d4e361f78e4d1b79425dfae912f05c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 13 Jun 2022 01:27:09 +0200 Subject: compiler_rt: use single cache for libcompiler_rt.a static lib --- CMakeLists.txt | 1 + lib/compiler_rt/os_version_check.zig | 13 +- src/Compilation.zig | 8 +- src/compiler_rt.zig | 226 +++++++++++++++++++++-------------- src/link/Coff.zig | 2 +- src/link/Elf.zig | 2 +- src/link/MachO.zig | 2 +- src/link/Wasm.zig | 2 +- 8 files changed, 151 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index cc962fcff1..7329c05918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -490,6 +490,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/ceil.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/clear_cache.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmp.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/common.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/compareXf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cos.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/count0bits.zig" diff --git a/lib/compiler_rt/os_version_check.zig b/lib/compiler_rt/os_version_check.zig index 53f332b13e..2c6cdb54dc 100644 --- a/lib/compiler_rt/os_version_check.zig +++ b/lib/compiler_rt/os_version_check.zig @@ -6,10 +6,7 @@ pub const panic = @import("common.zig").panic; comptime { if (builtin.os.tag.isDarwin()) { - @export(IsPlatformVersionAtLeast.__isPlatformVersionAtLeast, .{ - .name = "__isPlatformVersionAtLeast", - .linkage = linkage, - }); + @export(__isPlatformVersionAtLeast, .{ .name = "__isPlatformVersionAtLeast", .linkage = linkage }); } } @@ -28,7 +25,7 @@ comptime { // the newer codepath, which merely calls out to the Darwin _availability_version_check API which is // available on macOS 10.15+, iOS 13+, tvOS 13+ and watchOS 6+. -const IsPlatformVersionAtLeast = struct { +const __isPlatformVersionAtLeast = if (builtin.os.tag.isDarwin()) struct { inline fn constructVersion(major: u32, minor: u32, subminor: u32) u32 { return ((major & 0xffff) << 16) | ((minor & 0xff) << 8) | (subminor & 0xff); } @@ -50,7 +47,7 @@ const IsPlatformVersionAtLeast = struct { }; // Darwin-only extern "c" fn _availability_version_check(count: u32, versions: [*c]const dyld_build_version_t) bool; -}; +}.__isPlatformVersionAtLeast else struct {}; test "isPlatformVersionAtLeast" { if (!comptime builtin.os.tag.isDarwin()) return error.SkipZigTest; @@ -58,6 +55,6 @@ test "isPlatformVersionAtLeast" { // Note: this test depends on the actual host OS version since it is merely calling into the // native Darwin API. const macos_platform_constant = 1; - try testing.expect(IsPlatformVersionAtLeast.__isPlatformVersionAtLeast(macos_platform_constant, 10, 0, 15) == 1); - try testing.expect(IsPlatformVersionAtLeast.__isPlatformVersionAtLeast(macos_platform_constant, 99, 0, 0) == 0); + try testing.expect(__isPlatformVersionAtLeast(macos_platform_constant, 10, 0, 15) == 1); + try testing.expect(__isPlatformVersionAtLeast(macos_platform_constant, 99, 0, 0) == 0); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 0cd40a7001..2858a28f42 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -132,7 +132,7 @@ libssp_static_lib: ?CRTFile = null, libc_static_lib: ?CRTFile = null, /// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). -compiler_rt_static_lib: compiler_rt.CompilerRtLib = .{}, +compiler_rt_lib: ?CRTFile = null, /// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). compiler_rt_obj: ?CRTFile = null, @@ -1979,7 +1979,9 @@ pub fn destroy(self: *Compilation) void { if (self.libcxxabi_static_lib) |*crt_file| { crt_file.deinit(gpa); } - self.compiler_rt_static_lib.deinit(gpa); + if (self.compiler_rt_lib) |*crt_file| { + crt_file.deinit(gpa); + } if (self.compiler_rt_obj) |*crt_file| { crt_file.deinit(gpa); } @@ -3139,7 +3141,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { compiler_rt.buildCompilerRtLib( comp, - &comp.compiler_rt_static_lib, + &comp.compiler_rt_lib, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 82b482daa8..8df14de38c 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -1,123 +1,169 @@ const std = @import("std"); const builtin = @import("builtin"); +const build_options = @import("build_options"); const Allocator = std.mem.Allocator; +const assert = std.debug.assert; const mem = std.mem; const tracy = @import("tracy.zig"); const trace = tracy.trace; +const Cache = @import("Cache.zig"); const Compilation = @import("Compilation.zig"); const CRTFile = Compilation.CRTFile; const LinkObject = Compilation.LinkObject; const Package = @import("Package.zig"); -pub const CompilerRtLib = struct { - crt_object_files: [sources.len]?CRTFile = undefined, - crt_lib_file: ?CRTFile = null, - - pub fn deinit(crt_lib: *CompilerRtLib, gpa: Allocator) void { - for (crt_lib.crt_object_files) |*crt_file| { - if (crt_file.*) |*cf| { - cf.deinit(gpa); - } - } - if (crt_lib.crt_lib_file) |*crt_file| { - crt_file.deinit(gpa); - } - } -}; - -pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *CompilerRtLib) !void { +pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *?CRTFile) !void { const tracy_trace = trace(@src()); defer tracy_trace.end(); - var progress: std.Progress = .{ .dont_print_on_dumb = true }; - var progress_node = progress.start("Compile Compiler-RT", sources.len + 1); - defer progress_node.end(); - if (comp.color == .off) progress.terminal = null; + var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); - progress_node.activate(); + const target = comp.getTarget(); - var link_objects: [sources.len]LinkObject = undefined; - for (sources) |source, i| { - var obj_progress_node = progress_node.start(source, 0); - obj_progress_node.activate(); - defer obj_progress_node.end(); + // Use the global cache directory. + var cache_parent: Cache = .{ + .gpa = comp.gpa, + .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}), + }; + defer cache_parent.manifest_dir.close(); - try comp.buildOutputFromZig(source, .Obj, &compiler_rt_lib.crt_object_files[i], .compiler_rt); - link_objects[i] = .{ - .path = compiler_rt_lib.crt_object_files[i].?.full_object_path, - .must_link = true, - }; + var cache = cache_parent.obtain(); + defer cache.deinit(); + + cache.hash.add(sources.len); + for (sources) |source| { + const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{source}); + _ = try cache.addFile(full_path, null); } - const root_name = "compiler_rt"; + cache.hash.addBytes(build_options.version); + cache.hash.addBytes(comp.zig_lib_directory.path orelse "."); + cache.hash.add(target.cpu.arch); + cache.hash.add(target.os.tag); + cache.hash.add(target.abi); - var lib_progress_node = progress_node.start(root_name, 0); - lib_progress_node.activate(); - defer lib_progress_node.end(); + const hit = try cache.hit(); + const digest = cache.final(); + const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); - const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(comp.gpa, .{ + var o_directory: Compilation.Directory = .{ + .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}), + .path = try std.fs.path.join(arena, &[_][]const u8{ comp.global_cache_directory.path.?, o_sub_path }), + }; + defer o_directory.handle.close(); + + const ok_basename = "ok"; + const actual_hit = if (hit) blk: { + o_directory.handle.access(ok_basename, .{}) catch |err| switch (err) { + error.FileNotFound => break :blk false, + else => |e| return e, + }; + break :blk true; + } else false; + + const root_name = "compiler_rt"; + const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, .output_mode = .Lib, }); - errdefer comp.gpa.free(basename); - // TODO: This is extracted into a local variable to work around a stage1 miscompilation. - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; - const sub_compilation = try Compilation.create(comp.gpa, .{ - .local_cache_directory = comp.global_cache_directory, - .global_cache_directory = comp.global_cache_directory, - .zig_lib_directory = comp.zig_lib_directory, - .cache_mode = .whole, - .target = target, - .root_name = root_name, - .main_pkg = null, - .output_mode = .Lib, - .link_mode = .Static, - .function_sections = true, - .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, - .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .want_sanitize_c = false, - .want_stack_check = false, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = comp.bin_file.options.pie, - .want_lto = comp.bin_file.options.lto, - .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, - .link_objects = &link_objects, - .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, - .parent_compilation_link_libc = comp.bin_file.options.link_libc, - }); - defer sub_compilation.destroy(); + if (!actual_hit) { + var progress: std.Progress = .{ .dont_print_on_dumb = true }; + var progress_node = progress.start("Compile Compiler-RT", sources.len + 1); + defer progress_node.end(); + if (comp.color == .off) progress.terminal = null; + + progress_node.activate(); + + var link_objects: [sources.len]LinkObject = undefined; + for (sources) |source, i| { + var obj_progress_node = progress_node.start(source, 0); + obj_progress_node.activate(); + defer obj_progress_node.end(); + + var tmp_crt_file: ?CRTFile = null; + defer if (tmp_crt_file) |*crt| crt.deinit(comp.gpa); + try comp.buildOutputFromZig(source, .Obj, &tmp_crt_file, .compiler_rt); + link_objects[i] = .{ + .path = try arena.dupe(u8, tmp_crt_file.?.full_object_path), + .must_link = true, + }; + } + + var lib_progress_node = progress_node.start(root_name, 0); + lib_progress_node.activate(); + defer lib_progress_node.end(); + + // TODO: This is extracted into a local variable to work around a stage1 miscompilation. + const emit_bin = Compilation.EmitLoc{ + .directory = o_directory, // Put it in the cache directory. + .basename = basename, + }; + const sub_compilation = try Compilation.create(comp.gpa, .{ + .local_cache_directory = comp.global_cache_directory, + .global_cache_directory = comp.global_cache_directory, + .zig_lib_directory = comp.zig_lib_directory, + .cache_mode = .whole, + .target = target, + .root_name = root_name, + .main_pkg = null, + .output_mode = .Lib, + .link_mode = .Static, + .function_sections = true, + .thread_pool = comp.thread_pool, + .libc_installation = comp.bin_file.options.libc_installation, + .emit_bin = emit_bin, + .optimize_mode = comp.compilerRtOptMode(), + .want_sanitize_c = false, + .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, + .want_valgrind = false, + .want_tsan = false, + .want_pic = comp.bin_file.options.pic, + .want_pie = comp.bin_file.options.pie, + .want_lto = comp.bin_file.options.lto, + .emit_h = null, + .strip = comp.compilerRtStrip(), + .is_native_os = comp.bin_file.options.is_native_os, + .is_native_abi = comp.bin_file.options.is_native_abi, + .self_exe_path = comp.self_exe_path, + .link_objects = &link_objects, + .verbose_cc = comp.verbose_cc, + .verbose_link = comp.bin_file.options.verbose_link, + .verbose_air = comp.verbose_air, + .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_cimport = comp.verbose_cimport, + .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, + .clang_passthrough_mode = comp.clang_passthrough_mode, + .skip_linker_dependencies = true, + .parent_compilation_link_libc = comp.bin_file.options.link_libc, + }); + defer sub_compilation.destroy(); + + try sub_compilation.updateSubCompilation(); + + if (o_directory.handle.createFile(ok_basename, .{})) |file| { + file.close(); + } else |err| { + std.log.warn("compiler-rt lib: failed to mark completion: {s}", .{@errorName(err)}); + } + } - try sub_compilation.updateSubCompilation(); + try cache.writeManifest(); - compiler_rt_lib.crt_lib_file = .{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + assert(compiler_rt_lib.* == null); + compiler_rt_lib.* = .{ + .full_object_path = try std.fs.path.join(comp.gpa, &[_][]const u8{ + comp.global_cache_directory.path.?, + o_sub_path, + basename, }), - .lock = sub_compilation.bin_file.toOwnedLock(), + .lock = cache.toOwnedLock(), }; } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 4ab7cee6e1..2943cae36a 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1354,7 +1354,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! } // MSVC compiler_rt is missing some stuff, so we build it unconditionally but // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. - if (comp.compiler_rt_static_lib.crt_lib_file) |lib| { + if (comp.compiler_rt_lib) |lib| { try argv.append(lib.full_object_path); } } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 046aa2ec0a..a0e40e5682 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1272,7 +1272,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const stack_size = self.base.options.stack_size_override orelse 16777216; const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; const compiler_rt_path: ?[]const u8 = blk: { - if (comp.compiler_rt_static_lib.crt_lib_file) |x| break :blk x.full_object_path; + if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; break :blk null; }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 780b4b0483..92a651ad7d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -738,7 +738,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try positionals.append(p); } - if (comp.compiler_rt_static_lib.crt_lib_file) |lib| { + if (comp.compiler_rt_lib) |lib| { try positionals.append(lib.full_object_path); } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 30a1c49794..5a910e188b 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2255,7 +2255,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const is_obj = self.base.options.output_mode == .Obj; const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj) - comp.compiler_rt_static_lib.crt_lib_file.?.full_object_path + comp.compiler_rt_lib.?.full_object_path else null; -- cgit v1.2.3 From 57c530155f0c7754386c50fb9bc128198cab705c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 13 Jun 2022 19:21:38 +0200 Subject: compiler_rt: correctly export allrem and aullrem for i386-windows-msvc --- lib/compiler_rt.zig | 1 + lib/compiler_rt/aulldiv.zig | 2 -- lib/compiler_rt/aullrem.zig | 13 +++++++++++++ src/compiler_rt.zig | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 92d783cc25..999cce3e65 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -62,6 +62,7 @@ comptime { _ = @import("compiler_rt/emutls.zig"); _ = @import("compiler_rt/arm.zig"); _ = @import("compiler_rt/aulldiv.zig"); + _ = @import("compiler_rt/aullrem.zig"); _ = @import("compiler_rt/sparc.zig"); _ = @import("compiler_rt/clear_cache.zig"); diff --git a/lib/compiler_rt/aulldiv.zig b/lib/compiler_rt/aulldiv.zig index 7154cb39a1..38009d7015 100644 --- a/lib/compiler_rt/aulldiv.zig +++ b/lib/compiler_rt/aulldiv.zig @@ -10,8 +10,6 @@ comptime { // Don't let LLVM apply the stdcall name mangling on those MSVC builtins @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = linkage }); @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = linkage }); - @export(_allrem, .{ .name = "\x01__allrem", .linkage = linkage }); - @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = linkage }); } } diff --git a/lib/compiler_rt/aullrem.zig b/lib/compiler_rt/aullrem.zig index dbd52cd377..18e9eea0c6 100644 --- a/lib/compiler_rt/aullrem.zig +++ b/lib/compiler_rt/aullrem.zig @@ -1,4 +1,17 @@ +const std = @import("std"); const builtin = @import("builtin"); +const arch = builtin.cpu.arch; +const abi = builtin.abi; +const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Strong; +pub const panic = @import("common.zig").panic; + +comptime { + if (arch == .i386 and abi == .msvc) { + // Don't let LLVM apply the stdcall name mangling on those MSVC builtins + @export(_allrem, .{ .name = "\x01__allrem", .linkage = linkage }); + @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = linkage }); + } +} pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { @setRuntimeSafety(builtin.is_test); diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 8df14de38c..5149ce192f 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -227,6 +227,7 @@ const sources = &[_][]const u8{ "compiler_rt/emutls.zig", "compiler_rt/arm.zig", "compiler_rt/aulldiv.zig", + "compiler_rt/aullrem.zig", "compiler_rt/sparc.zig", "compiler_rt/clear_cache.zig", }; -- cgit v1.2.3 From 47c834e477657113bccaaad32e91148ff837f1a4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 14 Jun 2022 14:12:12 +0200 Subject: macho: unify flushing object path with other linkers --- src/link.zig | 7 ++----- src/link/MachO.zig | 44 +++++++++++++++++++------------------------- 2 files changed, 21 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/link.zig b/src/link.zig index 51712db40e..65e9de8ca3 100644 --- a/src/link.zig +++ b/src/link.zig @@ -792,11 +792,8 @@ pub const File = struct { }), } } - if (base.options.object_format == .macho) { - try base.cast(MachO).?.flushObject(comp, prog_node); - } else { - try base.flushModule(comp, prog_node); - } + try base.flushModule(comp, prog_node); + const dirname = fs.path.dirname(full_out_path_z) orelse "."; break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? }); } else null; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 92a651ad7d..44d763289a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -436,7 +436,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !v return error.TODOImplementWritingStaticLibFiles; } } - try self.flushModule(comp, prog_node); + return self.flushModule(comp, prog_node); } pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { @@ -444,8 +444,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No defer tracy.end(); const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; - if (!use_stage1 and self.base.options.output_mode == .Obj) - return self.flushObject(comp, prog_node); + + if (build_options.have_llvm and !use_stage1) { + if (self.llvm_object) |llvm_object| { + try llvm_object.flushModule(comp, prog_node); + + llvm_object.destroy(self.base.allocator); + self.llvm_object = null; + } + } + + var sub_prog_node = prog_node.start("MachO Flush", 0); + sub_prog_node.activate(); + defer sub_prog_node.end(); var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); defer arena_allocator.deinit(); @@ -454,12 +465,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); - if (self.d_sym) |*d_sym| { - if (self.base.options.module) |module| { - try d_sym.dwarf.flushModule(&self.base, module); - } - } - // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { @@ -482,8 +487,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const obj_basename = self.base.intermediary_basename orelse break :blk null; - try self.flushObject(comp, prog_node); - if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, obj_basename }); } else { @@ -491,9 +494,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No } } else null; - var sub_prog_node = prog_node.start("MachO Flush", 0); - sub_prog_node.activate(); - defer sub_prog_node.end(); + if (self.d_sym) |*d_sym| { + if (self.base.options.module) |module| { + try d_sym.dwarf.flushModule(&self.base, module); + } + } const is_lib = self.base.options.output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; @@ -1119,17 +1124,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No self.cold_start = false; } -pub fn flushObject(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { - const tracy = trace(@src()); - defer tracy.end(); - - if (build_options.have_llvm) - if (self.llvm_object) |llvm_object| - return llvm_object.flushModule(comp, prog_node); - - return error.TODOImplementWritingObjFiles; -} - fn resolveSearchDir( arena: Allocator, dir: []const u8, -- cgit v1.2.3 From c99c085d70c9347ec9a15d9a4f73c19e628912b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 15 Jun 2022 23:09:56 -0700 Subject: compiler-rt: break up functions even more The purpose of this branch is to switch to using an object file for each independent function, in order to make linking simpler - instead of relying on `-ffunction-sections` and `--gc-sections`, which involves the linker doing the work of linking everything and then undoing work via garbage collection, this will allow the linker to only include the compilation units that are depended on in the first place. This commit makes progress towards that goal. --- CMakeLists.txt | 101 +++- lib/compiler_rt.zig | 147 +++++- lib/compiler_rt/absv.zig | 30 +- lib/compiler_rt/absvdi2.zig | 12 + lib/compiler_rt/absvsi2.zig | 12 + lib/compiler_rt/absvti2.zig | 12 + lib/compiler_rt/addXf3.zig | 271 ---------- lib/compiler_rt/addXf3_test.zig | 157 ------ lib/compiler_rt/adddf3.zig | 20 + lib/compiler_rt/addf3.zig | 172 ++++++ lib/compiler_rt/addf3_test.zig | 157 ++++++ lib/compiler_rt/addsf3.zig | 20 + lib/compiler_rt/addtf3.zig | 20 + lib/compiler_rt/addxf3.zig | 12 + lib/compiler_rt/cmpdf2.zig | 68 +++ lib/compiler_rt/cmpsf2.zig | 68 +++ lib/compiler_rt/cmptf2.zig | 73 +++ lib/compiler_rt/cmpxf2.zig | 50 ++ lib/compiler_rt/common.zig | 27 +- lib/compiler_rt/compareXf2.zig | 440 ---------------- lib/compiler_rt/comparef.zig | 118 +++++ lib/compiler_rt/extendXfYf2.zig | 148 ------ lib/compiler_rt/extend_f80.zig | 140 ----- lib/compiler_rt/extenddftf2.zig | 20 + lib/compiler_rt/extenddfxf2.zig | 12 + lib/compiler_rt/extendf.zig | 142 +++++ lib/compiler_rt/extendhfsf2.zig | 26 + lib/compiler_rt/extendhftf2.zig | 12 + lib/compiler_rt/extendhfxf2.zig | 12 + lib/compiler_rt/extendsfdf2.zig | 20 + lib/compiler_rt/extendsftf2.zig | 20 + lib/compiler_rt/extendsfxf2.zig | 12 + lib/compiler_rt/extendxftf2.zig | 50 ++ lib/compiler_rt/fixXfYi.zig | 312 ----------- lib/compiler_rt/fixXfYi_test.zig | 948 ---------------------------------- lib/compiler_rt/fixdfdi.zig | 20 + lib/compiler_rt/fixdfsi.zig | 20 + lib/compiler_rt/fixdfti.zig | 12 + lib/compiler_rt/fixhfdi.zig | 12 + lib/compiler_rt/fixhfsi.zig | 12 + lib/compiler_rt/fixhfti.zig | 12 + lib/compiler_rt/fixsfdi.zig | 20 + lib/compiler_rt/fixsfsi.zig | 20 + lib/compiler_rt/fixsfti.zig | 12 + lib/compiler_rt/fixtfdi.zig | 20 + lib/compiler_rt/fixtfsi.zig | 20 + lib/compiler_rt/fixtfti.zig | 12 + lib/compiler_rt/fixunsdfdi.zig | 20 + lib/compiler_rt/fixunsdfsi.zig | 20 + lib/compiler_rt/fixunsdfti.zig | 12 + lib/compiler_rt/fixunshfdi.zig | 12 + lib/compiler_rt/fixunshfsi.zig | 12 + lib/compiler_rt/fixunshfti.zig | 12 + lib/compiler_rt/fixunssfdi.zig | 20 + lib/compiler_rt/fixunssfsi.zig | 20 + lib/compiler_rt/fixunssfti.zig | 12 + lib/compiler_rt/fixunstfdi.zig | 20 + lib/compiler_rt/fixunstfsi.zig | 20 + lib/compiler_rt/fixunstfti.zig | 12 + lib/compiler_rt/fixunsxfdi.zig | 12 + lib/compiler_rt/fixunsxfsi.zig | 12 + lib/compiler_rt/fixunsxfti.zig | 12 + lib/compiler_rt/fixxfdi.zig | 12 + lib/compiler_rt/fixxfsi.zig | 12 + lib/compiler_rt/fixxfti.zig | 12 + lib/compiler_rt/floatXiYf.zig | 311 ----------- lib/compiler_rt/float_to_int.zig | 55 ++ lib/compiler_rt/float_to_int_test.zig | 948 ++++++++++++++++++++++++++++++++++ lib/compiler_rt/floatdidf.zig | 20 + lib/compiler_rt/floatdihf.zig | 12 + lib/compiler_rt/floatdisf.zig | 20 + lib/compiler_rt/floatditf.zig | 20 + lib/compiler_rt/floatdixf.zig | 12 + lib/compiler_rt/floatsidf.zig | 20 + lib/compiler_rt/floatsihf.zig | 12 + lib/compiler_rt/floatsisf.zig | 20 + lib/compiler_rt/floatsitf.zig | 20 + lib/compiler_rt/floatsixf.zig | 12 + lib/compiler_rt/floattidf.zig | 12 + lib/compiler_rt/floattihf.zig | 12 + lib/compiler_rt/floattisf.zig | 12 + lib/compiler_rt/floattitf.zig | 12 + lib/compiler_rt/floattixf.zig | 12 + lib/compiler_rt/floatundidf.zig | 20 + lib/compiler_rt/floatundihf.zig | 12 + lib/compiler_rt/floatundisf.zig | 20 + lib/compiler_rt/floatunditf.zig | 20 + lib/compiler_rt/floatundixf.zig | 12 + lib/compiler_rt/floatunsidf.zig | 20 + lib/compiler_rt/floatunsihf.zig | 12 + lib/compiler_rt/floatunsisf.zig | 20 + lib/compiler_rt/floatunsitf.zig | 20 + lib/compiler_rt/floatunsixf.zig | 12 + lib/compiler_rt/floatuntidf.zig | 12 + lib/compiler_rt/floatuntihf.zig | 12 + lib/compiler_rt/floatuntisf.zig | 12 + lib/compiler_rt/floatuntitf.zig | 20 + lib/compiler_rt/floatuntixf.zig | 12 + lib/compiler_rt/gedf2.zig | 36 ++ lib/compiler_rt/gesf2.zig | 36 ++ lib/compiler_rt/getf2.zig | 36 ++ lib/compiler_rt/gexf2.zig | 17 + lib/compiler_rt/int_to_float.zig | 58 +++ lib/compiler_rt/mulXf3.zig | 368 ------------- lib/compiler_rt/mulXf3_test.zig | 171 ------ lib/compiler_rt/muldf3.zig | 20 + lib/compiler_rt/mulf3.zig | 203 ++++++++ lib/compiler_rt/mulf3_test.zig | 171 ++++++ lib/compiler_rt/mulsf3.zig | 20 + lib/compiler_rt/multf3.zig | 20 + lib/compiler_rt/mulxf3.zig | 12 + lib/compiler_rt/sparc.zig | 6 +- lib/compiler_rt/subdf3.zig | 21 + lib/compiler_rt/subsf3.zig | 21 + lib/compiler_rt/subtf3.zig | 21 + lib/compiler_rt/subxf3.zig | 15 + lib/compiler_rt/truncXfYf2.zig | 192 ------- lib/compiler_rt/truncXfYf2_test.zig | 296 ----------- lib/compiler_rt/trunc_f80.zig | 183 ------- lib/compiler_rt/truncdfhf2.zig | 20 + lib/compiler_rt/truncdfsf2.zig | 20 + lib/compiler_rt/truncf.zig | 187 +++++++ lib/compiler_rt/truncf_test.zig | 310 +++++++++++ lib/compiler_rt/truncsfhf2.zig | 26 + lib/compiler_rt/trunctfdf2.zig | 20 + lib/compiler_rt/trunctfhf2.zig | 12 + lib/compiler_rt/trunctfsf2.zig | 20 + lib/compiler_rt/trunctfxf2.zig | 66 +++ lib/compiler_rt/truncxfdf2.zig | 12 + lib/compiler_rt/truncxfhf2.zig | 12 + lib/compiler_rt/truncxfsf2.zig | 12 + lib/compiler_rt/unorddf2.zig | 20 + lib/compiler_rt/unordsf2.zig | 20 + lib/compiler_rt/unordtf2.zig | 20 + src/compiler_rt.zig | 4 +- 135 files changed, 4791 insertions(+), 4008 deletions(-) create mode 100644 lib/compiler_rt/absvdi2.zig create mode 100644 lib/compiler_rt/absvsi2.zig create mode 100644 lib/compiler_rt/absvti2.zig delete mode 100644 lib/compiler_rt/addXf3.zig delete mode 100644 lib/compiler_rt/addXf3_test.zig create mode 100644 lib/compiler_rt/adddf3.zig create mode 100644 lib/compiler_rt/addf3.zig create mode 100644 lib/compiler_rt/addf3_test.zig create mode 100644 lib/compiler_rt/addsf3.zig create mode 100644 lib/compiler_rt/addtf3.zig create mode 100644 lib/compiler_rt/addxf3.zig create mode 100644 lib/compiler_rt/cmpdf2.zig create mode 100644 lib/compiler_rt/cmpsf2.zig create mode 100644 lib/compiler_rt/cmptf2.zig create mode 100644 lib/compiler_rt/cmpxf2.zig delete mode 100644 lib/compiler_rt/compareXf2.zig create mode 100644 lib/compiler_rt/comparef.zig delete mode 100644 lib/compiler_rt/extendXfYf2.zig delete mode 100644 lib/compiler_rt/extend_f80.zig create mode 100644 lib/compiler_rt/extenddftf2.zig create mode 100644 lib/compiler_rt/extenddfxf2.zig create mode 100644 lib/compiler_rt/extendf.zig create mode 100644 lib/compiler_rt/extendhfsf2.zig create mode 100644 lib/compiler_rt/extendhftf2.zig create mode 100644 lib/compiler_rt/extendhfxf2.zig create mode 100644 lib/compiler_rt/extendsfdf2.zig create mode 100644 lib/compiler_rt/extendsftf2.zig create mode 100644 lib/compiler_rt/extendsfxf2.zig create mode 100644 lib/compiler_rt/extendxftf2.zig delete mode 100644 lib/compiler_rt/fixXfYi.zig delete mode 100644 lib/compiler_rt/fixXfYi_test.zig create mode 100644 lib/compiler_rt/fixdfdi.zig create mode 100644 lib/compiler_rt/fixdfsi.zig create mode 100644 lib/compiler_rt/fixdfti.zig create mode 100644 lib/compiler_rt/fixhfdi.zig create mode 100644 lib/compiler_rt/fixhfsi.zig create mode 100644 lib/compiler_rt/fixhfti.zig create mode 100644 lib/compiler_rt/fixsfdi.zig create mode 100644 lib/compiler_rt/fixsfsi.zig create mode 100644 lib/compiler_rt/fixsfti.zig create mode 100644 lib/compiler_rt/fixtfdi.zig create mode 100644 lib/compiler_rt/fixtfsi.zig create mode 100644 lib/compiler_rt/fixtfti.zig create mode 100644 lib/compiler_rt/fixunsdfdi.zig create mode 100644 lib/compiler_rt/fixunsdfsi.zig create mode 100644 lib/compiler_rt/fixunsdfti.zig create mode 100644 lib/compiler_rt/fixunshfdi.zig create mode 100644 lib/compiler_rt/fixunshfsi.zig create mode 100644 lib/compiler_rt/fixunshfti.zig create mode 100644 lib/compiler_rt/fixunssfdi.zig create mode 100644 lib/compiler_rt/fixunssfsi.zig create mode 100644 lib/compiler_rt/fixunssfti.zig create mode 100644 lib/compiler_rt/fixunstfdi.zig create mode 100644 lib/compiler_rt/fixunstfsi.zig create mode 100644 lib/compiler_rt/fixunstfti.zig create mode 100644 lib/compiler_rt/fixunsxfdi.zig create mode 100644 lib/compiler_rt/fixunsxfsi.zig create mode 100644 lib/compiler_rt/fixunsxfti.zig create mode 100644 lib/compiler_rt/fixxfdi.zig create mode 100644 lib/compiler_rt/fixxfsi.zig create mode 100644 lib/compiler_rt/fixxfti.zig delete mode 100644 lib/compiler_rt/floatXiYf.zig create mode 100644 lib/compiler_rt/float_to_int.zig create mode 100644 lib/compiler_rt/float_to_int_test.zig create mode 100644 lib/compiler_rt/floatdidf.zig create mode 100644 lib/compiler_rt/floatdihf.zig create mode 100644 lib/compiler_rt/floatdisf.zig create mode 100644 lib/compiler_rt/floatditf.zig create mode 100644 lib/compiler_rt/floatdixf.zig create mode 100644 lib/compiler_rt/floatsidf.zig create mode 100644 lib/compiler_rt/floatsihf.zig create mode 100644 lib/compiler_rt/floatsisf.zig create mode 100644 lib/compiler_rt/floatsitf.zig create mode 100644 lib/compiler_rt/floatsixf.zig create mode 100644 lib/compiler_rt/floattidf.zig create mode 100644 lib/compiler_rt/floattihf.zig create mode 100644 lib/compiler_rt/floattisf.zig create mode 100644 lib/compiler_rt/floattitf.zig create mode 100644 lib/compiler_rt/floattixf.zig create mode 100644 lib/compiler_rt/floatundidf.zig create mode 100644 lib/compiler_rt/floatundihf.zig create mode 100644 lib/compiler_rt/floatundisf.zig create mode 100644 lib/compiler_rt/floatunditf.zig create mode 100644 lib/compiler_rt/floatundixf.zig create mode 100644 lib/compiler_rt/floatunsidf.zig create mode 100644 lib/compiler_rt/floatunsihf.zig create mode 100644 lib/compiler_rt/floatunsisf.zig create mode 100644 lib/compiler_rt/floatunsitf.zig create mode 100644 lib/compiler_rt/floatunsixf.zig create mode 100644 lib/compiler_rt/floatuntidf.zig create mode 100644 lib/compiler_rt/floatuntihf.zig create mode 100644 lib/compiler_rt/floatuntisf.zig create mode 100644 lib/compiler_rt/floatuntitf.zig create mode 100644 lib/compiler_rt/floatuntixf.zig create mode 100644 lib/compiler_rt/gedf2.zig create mode 100644 lib/compiler_rt/gesf2.zig create mode 100644 lib/compiler_rt/getf2.zig create mode 100644 lib/compiler_rt/gexf2.zig create mode 100644 lib/compiler_rt/int_to_float.zig delete mode 100644 lib/compiler_rt/mulXf3.zig delete mode 100644 lib/compiler_rt/mulXf3_test.zig create mode 100644 lib/compiler_rt/muldf3.zig create mode 100644 lib/compiler_rt/mulf3.zig create mode 100644 lib/compiler_rt/mulf3_test.zig create mode 100644 lib/compiler_rt/mulsf3.zig create mode 100644 lib/compiler_rt/multf3.zig create mode 100644 lib/compiler_rt/mulxf3.zig create mode 100644 lib/compiler_rt/subdf3.zig create mode 100644 lib/compiler_rt/subsf3.zig create mode 100644 lib/compiler_rt/subtf3.zig create mode 100644 lib/compiler_rt/subxf3.zig delete mode 100644 lib/compiler_rt/truncXfYf2.zig delete mode 100644 lib/compiler_rt/truncXfYf2_test.zig delete mode 100644 lib/compiler_rt/trunc_f80.zig create mode 100644 lib/compiler_rt/truncdfhf2.zig create mode 100644 lib/compiler_rt/truncdfsf2.zig create mode 100644 lib/compiler_rt/truncf.zig create mode 100644 lib/compiler_rt/truncf_test.zig create mode 100644 lib/compiler_rt/truncsfhf2.zig create mode 100644 lib/compiler_rt/trunctfdf2.zig create mode 100644 lib/compiler_rt/trunctfhf2.zig create mode 100644 lib/compiler_rt/trunctfsf2.zig create mode 100644 lib/compiler_rt/trunctfxf2.zig create mode 100644 lib/compiler_rt/truncxfdf2.zig create mode 100644 lib/compiler_rt/truncxfhf2.zig create mode 100644 lib/compiler_rt/truncxfsf2.zig create mode 100644 lib/compiler_rt/unorddf2.zig create mode 100644 lib/compiler_rt/unordsf2.zig create mode 100644 lib/compiler_rt/unordtf2.zig (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 7329c05918..a393249458 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -480,7 +480,14 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/absv.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addXf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addsf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addtf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addxf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/addo.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/arm.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/atomics.zig" @@ -491,7 +498,18 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/clear_cache.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmp.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/common.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/compareXf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/comparef.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmptf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cmpxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gesf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gedf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/getf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/gexf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unorddf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/unordtf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/cos.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/count0bits.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/divdf3.zig" @@ -502,11 +520,79 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/emutls.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/exp2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendXfYf2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extend_f80.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extenddfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfsf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendhfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfdf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsftf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendsfxf2.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/extendxftf2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fabs.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixXfYi.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatXiYf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/int_to_float.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatsixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatditf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatdixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floattixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunditf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatundixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatunsixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntihf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntisf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntidf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntitf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floatuntixf.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/float_to_int.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixhfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixsfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixdfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixtfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixxfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunshfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunssfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsdfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunstfti.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfsi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfdi.zig" + "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fixunsxfti.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/floor.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fma.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/fmax.zig" @@ -517,7 +603,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulXf3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig" @@ -541,8 +626,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/truncXfYf2.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc_f80.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmod.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivmodti4.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/udivti3.zig" diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index fec4573f46..826530286d 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -1,18 +1,59 @@ -const builtin = @import("builtin"); pub const panic = @import("compiler_rt/common.zig").panic; comptime { - // TODO moving these around makes or breaks compilation of zig1.o for some reason - // Perhaps, until we switch to stage2, exports should be duplicated between this file - // and files included as a standalone units? _ = @import("compiler_rt/atomics.zig"); - _ = @import("compiler_rt/addXf3.zig"); - _ = @import("compiler_rt/mulXf3.zig"); - _ = @import("compiler_rt/compareXf2.zig"); - _ = @import("compiler_rt/extendXfYf2.zig"); - _ = @import("compiler_rt/extend_f80.zig"); - _ = @import("compiler_rt/truncXfYf2.zig"); - _ = @import("compiler_rt/trunc_f80.zig"); + + _ = @import("compiler_rt/addf3.zig"); + _ = @import("compiler_rt/addsf3.zig"); + _ = @import("compiler_rt/addtf3.zig"); + _ = @import("compiler_rt/addxf3.zig"); + _ = @import("compiler_rt/subdf3.zig"); + _ = @import("compiler_rt/subsf3.zig"); + _ = @import("compiler_rt/subtf3.zig"); + _ = @import("compiler_rt/subxf3.zig"); + + _ = @import("compiler_rt/mulf3.zig"); + _ = @import("compiler_rt/muldf3.zig"); + _ = @import("compiler_rt/mulsf3.zig"); + _ = @import("compiler_rt/multf3.zig"); + _ = @import("compiler_rt/mulxf3.zig"); + + _ = @import("compiler_rt/comparef.zig"); + _ = @import("compiler_rt/cmpsf2.zig"); + _ = @import("compiler_rt/cmpdf2.zig"); + _ = @import("compiler_rt/cmptf2.zig"); + _ = @import("compiler_rt/cmpxf2.zig"); + _ = @import("compiler_rt/gesf2.zig"); + _ = @import("compiler_rt/gedf2.zig"); + _ = @import("compiler_rt/getf2.zig"); + _ = @import("compiler_rt/gexf2.zig"); + _ = @import("compiler_rt/unordsf2.zig"); + _ = @import("compiler_rt/unorddf2.zig"); + _ = @import("compiler_rt/unordtf2.zig"); + + _ = @import("compiler_rt/extendf.zig"); + _ = @import("compiler_rt/extenddftf2.zig"); + _ = @import("compiler_rt/extenddfxf2.zig"); + _ = @import("compiler_rt/extendhfsf2.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/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/trunctfhf2.zig"); + _ = @import("compiler_rt/trunctfsf2.zig"); + _ = @import("compiler_rt/trunctfdf2.zig"); + _ = @import("compiler_rt/trunctfxf2.zig"); + _ = @import("compiler_rt/truncxfhf2.zig"); + _ = @import("compiler_rt/truncxfsf2.zig"); + _ = @import("compiler_rt/truncxfdf2.zig"); + _ = @import("compiler_rt/divtf3.zig"); _ = @import("compiler_rt/divsf3.zig"); _ = @import("compiler_rt/divdf3.zig"); @@ -43,35 +84,101 @@ comptime { _ = @import("compiler_rt/udivti3.zig"); _ = @import("compiler_rt/udivmodti4.zig"); _ = @import("compiler_rt/umodti3.zig"); - _ = @import("compiler_rt/floatXiYf.zig"); - _ = @import("compiler_rt/fixXfYi.zig"); + + _ = @import("compiler_rt/int_to_float.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/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/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/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/float_to_int.zig"); + _ = @import("compiler_rt/fixhfsi.zig"); + _ = @import("compiler_rt/fixhfdi.zig"); + _ = @import("compiler_rt/fixhfti.zig"); + _ = @import("compiler_rt/fixsfsi.zig"); + _ = @import("compiler_rt/fixsfdi.zig"); + _ = @import("compiler_rt/fixsfti.zig"); + _ = @import("compiler_rt/fixdfsi.zig"); + _ = @import("compiler_rt/fixdfdi.zig"); + _ = @import("compiler_rt/fixdfti.zig"); + _ = @import("compiler_rt/fixtfsi.zig"); + _ = @import("compiler_rt/fixtfdi.zig"); + _ = @import("compiler_rt/fixtfti.zig"); + _ = @import("compiler_rt/fixxfsi.zig"); + _ = @import("compiler_rt/fixxfdi.zig"); + _ = @import("compiler_rt/fixxfti.zig"); + _ = @import("compiler_rt/fixunshfsi.zig"); + _ = @import("compiler_rt/fixunshfdi.zig"); + _ = @import("compiler_rt/fixunshfti.zig"); + _ = @import("compiler_rt/fixunssfsi.zig"); + _ = @import("compiler_rt/fixunssfdi.zig"); + _ = @import("compiler_rt/fixunssfti.zig"); + _ = @import("compiler_rt/fixunsdfsi.zig"); + _ = @import("compiler_rt/fixunsdfdi.zig"); + _ = @import("compiler_rt/fixunsdfti.zig"); + _ = @import("compiler_rt/fixunstfsi.zig"); + _ = @import("compiler_rt/fixunstfdi.zig"); + _ = @import("compiler_rt/fixunstfti.zig"); + _ = @import("compiler_rt/fixunsxfsi.zig"); + _ = @import("compiler_rt/fixunsxfdi.zig"); + _ = @import("compiler_rt/fixunsxfti.zig"); + _ = @import("compiler_rt/count0bits.zig"); _ = @import("compiler_rt/parity.zig"); _ = @import("compiler_rt/popcount.zig"); _ = @import("compiler_rt/bswap.zig"); _ = @import("compiler_rt/int.zig"); _ = @import("compiler_rt/shift.zig"); + _ = @import("compiler_rt/negXi2.zig"); + _ = @import("compiler_rt/muldi3.zig"); + _ = @import("compiler_rt/absv.zig"); + _ = @import("compiler_rt/absvsi2.zig"); + _ = @import("compiler_rt/absvdi2.zig"); + _ = @import("compiler_rt/absvti2.zig"); + _ = @import("compiler_rt/negv.zig"); _ = @import("compiler_rt/addo.zig"); _ = @import("compiler_rt/subo.zig"); _ = @import("compiler_rt/mulo.zig"); _ = @import("compiler_rt/cmp.zig"); + _ = @import("compiler_rt/negXf2.zig"); + _ = @import("compiler_rt/os_version_check.zig"); _ = @import("compiler_rt/emutls.zig"); _ = @import("compiler_rt/arm.zig"); _ = @import("compiler_rt/aulldiv.zig"); _ = @import("compiler_rt/aullrem.zig"); - _ = @import("compiler_rt/sparc.zig"); _ = @import("compiler_rt/clear_cache.zig"); - // missing: Floating point raised to integer power - - // missing: Complex arithmetic - // (a + ib) * (c + id) - // (a + ib) / (c + id) - + _ = @import("compiler_rt/sparc.zig"); } diff --git a/lib/compiler_rt/absv.zig b/lib/compiler_rt/absv.zig index 3d9476b6c7..8910a4a6b9 100644 --- a/lib/compiler_rt/absv.zig +++ b/lib/compiler_rt/absv.zig @@ -1,18 +1,6 @@ -// absv - absolute oVerflow -// * @panic, if value can not be represented -// - absvXi4_generic for unoptimized version -const std = @import("std"); -const builtin = @import("builtin"); -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__absvsi2, .{ .name = "__absvsi2", .linkage = linkage }); - @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); - @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); -} - -inline fn absvXi(comptime ST: type, a: ST) ST { +/// absv - absolute oVerflow +/// * @panic if value can not be represented +pub inline fn absv(comptime ST: type, a: ST) ST { const UT = switch (ST) { i32 => u32, i64 => u64, @@ -31,18 +19,6 @@ inline fn absvXi(comptime ST: type, a: ST) ST { return x; } -pub fn __absvsi2(a: i32) callconv(.C) i32 { - return absvXi(i32, a); -} - -pub fn __absvdi2(a: i64) callconv(.C) i64 { - return absvXi(i64, a); -} - -pub fn __absvti2(a: i128) callconv(.C) i128 { - return absvXi(i128, a); -} - test { _ = @import("absvsi2_test.zig"); _ = @import("absvdi2_test.zig"); diff --git a/lib/compiler_rt/absvdi2.zig b/lib/compiler_rt/absvdi2.zig new file mode 100644 index 0000000000..1875d5bbaa --- /dev/null +++ b/lib/compiler_rt/absvdi2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvdi2, .{ .name = "__absvdi2", .linkage = common.linkage }); +} + +fn __absvdi2(a: i64) callconv(.C) i64 { + return absv(i64, a); +} diff --git a/lib/compiler_rt/absvsi2.zig b/lib/compiler_rt/absvsi2.zig new file mode 100644 index 0000000000..965e39bc9b --- /dev/null +++ b/lib/compiler_rt/absvsi2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvsi2, .{ .name = "__absvsi2", .linkage = common.linkage }); +} + +fn __absvsi2(a: i32) callconv(.C) i32 { + return absv(i32, a); +} diff --git a/lib/compiler_rt/absvti2.zig b/lib/compiler_rt/absvti2.zig new file mode 100644 index 0000000000..ada06c6563 --- /dev/null +++ b/lib/compiler_rt/absvti2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const absv = @import("./absv.zig").absv; + +pub const panic = common.panic; + +comptime { + @export(__absvti2, .{ .name = "__absvti2", .linkage = common.linkage }); +} + +fn __absvti2(a: i128) callconv(.C) i128 { + return absv(i128, a); +} diff --git a/lib/compiler_rt/addXf3.zig b/lib/compiler_rt/addXf3.zig deleted file mode 100644 index e2cf9d0112..0000000000 --- a/lib/compiler_rt/addXf3.zig +++ /dev/null @@ -1,271 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc - -const std = @import("std"); -const builtin = @import("builtin"); -const math = std.math; -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; - -const common = @import("common.zig"); -const normalize = common.normalize; -pub const panic = common.panic; - -comptime { - @export(__addsf3, .{ .name = "__addsf3", .linkage = linkage }); - @export(__adddf3, .{ .name = "__adddf3", .linkage = linkage }); - @export(__addxf3, .{ .name = "__addxf3", .linkage = linkage }); - @export(__addtf3, .{ .name = "__addtf3", .linkage = linkage }); - - @export(__subsf3, .{ .name = "__subsf3", .linkage = linkage }); - @export(__subdf3, .{ .name = "__subdf3", .linkage = linkage }); - @export(__subxf3, .{ .name = "__subxf3", .linkage = linkage }); - @export(__subtf3, .{ .name = "__subtf3", .linkage = linkage }); - - if (!is_test) { - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = linkage }); - @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = linkage }); - @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = linkage }); - @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__addkf3, .{ .name = "__addkf3", .linkage = linkage }); - @export(__subkf3, .{ .name = "__subkf3", .linkage = linkage }); - } - } -} - -pub fn __addsf3(a: f32, b: f32) callconv(.C) f32 { - return addXf3(f32, a, b); -} - -pub fn __adddf3(a: f64, b: f64) callconv(.C) f64 { - return addXf3(f64, a, b); -} - -pub fn __addxf3(a: f80, b: f80) callconv(.C) f80 { - return addXf3(f80, a, b); -} - -pub fn __subxf3(a: f80, b: f80) callconv(.C) f80 { - var b_rep = std.math.break_f80(b); - b_rep.exp ^= 0x8000; - return __addxf3(a, std.math.make_f80(b_rep)); -} - -pub fn __addtf3(a: f128, b: f128) callconv(.C) f128 { - return addXf3(f128, a, b); -} - -pub fn __addkf3(a: f128, b: f128) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __addtf3, .{ a, b }); -} - -pub fn __subsf3(a: f32, b: f32) callconv(.C) f32 { - const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); - return addXf3(f32, a, neg_b); -} - -pub fn __subdf3(a: f64, b: f64) callconv(.C) f64 { - const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); - return addXf3(f64, a, neg_b); -} - -pub fn __subtf3(a: f128, b: f128) callconv(.C) f128 { - const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); - return addXf3(f128, a, neg_b); -} - -pub fn __subkf3(a: f128, b: f128) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __subtf3, .{ a, b }); -} - -pub fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __addsf3, .{ a, b }); -} - -pub fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __adddf3, .{ a, b }); -} - -pub fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __subsf3, .{ a, b }); -} - -pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __subdf3, .{ a, b }); -} - -// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 -pub fn addXf3(comptime T: type, a: T, b: T) T { - const bits = @typeInfo(T).Float.bits; - const Z = std.meta.Int(.unsigned, bits); - const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); - - const typeWidth = bits; - const significandBits = math.floatMantissaBits(T); - const fractionalBits = math.floatFractionalBits(T); - const exponentBits = math.floatExponentBits(T); - - const signBit = (@as(Z, 1) << (significandBits + exponentBits)); - const maxExponent = ((1 << exponentBits) - 1); - - const integerBit = (@as(Z, 1) << fractionalBits); - const quietBit = integerBit >> 1; - const significandMask = (@as(Z, 1) << significandBits) - 1; - - const absMask = signBit - 1; - const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; - - var aRep = @bitCast(Z, a); - var bRep = @bitCast(Z, b); - const aAbs = aRep & absMask; - const bAbs = bRep & absMask; - - const infRep = @bitCast(Z, math.inf(T)); - - // Detect if a or b is zero, infinity, or NaN. - if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or - bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) - { - // NaN + anything = qNaN - if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); - // anything + NaN = qNaN - if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); - - if (aAbs == infRep) { - // +/-infinity + -/+infinity = qNaN - if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { - return @bitCast(T, qnanRep); - } - // +/-infinity + anything remaining = +/- infinity - else { - return a; - } - } - - // anything remaining + +/-infinity = +/-infinity - if (bAbs == infRep) return b; - - // zero + anything = anything - if (aAbs == 0) { - // but we need to get the sign right for zero + zero - if (bAbs == 0) { - return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); - } else { - return b; - } - } - - // anything + zero = anything - if (bAbs == 0) return a; - } - - // Swap a and b if necessary so that a has the larger absolute value. - if (bAbs > aAbs) { - const temp = aRep; - aRep = bRep; - bRep = temp; - } - - // Extract the exponent and significand from the (possibly swapped) a and b. - var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); - var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); - var aSignificand = aRep & significandMask; - var bSignificand = bRep & significandMask; - - // Normalize any denormals, and adjust the exponent accordingly. - if (aExponent == 0) aExponent = normalize(T, &aSignificand); - if (bExponent == 0) bExponent = normalize(T, &bSignificand); - - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - const resultSign = aRep & signBit; - const subtraction = (aRep ^ bRep) & signBit != 0; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize( ), but setting it twice won't hurt - // anything.) - aSignificand = (aSignificand | integerBit) << 3; - bSignificand = (bSignificand | integerBit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - const @"align" = @intCast(u32, aExponent - bExponent); - if (@"align" != 0) { - if (@"align" < typeWidth) { - const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; - bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; - } else { - bSignificand = 1; // sticky; b is known to be non-zero. - } - } - if (subtraction) { - aSignificand -= bSignificand; - // If a == -b, return +zero. - if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); - - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if (aSignificand < integerBit << 3) { - const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); - aSignificand <<= @intCast(S, shift); - aExponent -= shift; - } - } else { // addition - aSignificand += bSignificand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if (aSignificand & (integerBit << 4) != 0) { - const sticky = aSignificand & 1; - aSignificand = aSignificand >> 1 | sticky; - aExponent += 1; - } - } - - // If we have overflowed the type, return +/- infinity: - if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); - - if (aExponent <= 0) { - // Result is denormal; the exponent and round/sticky bits are zero. - // All we need to do is shift the significand and apply the correct sign. - aSignificand >>= @intCast(S, 4 - aExponent); - return @bitCast(T, resultSign | aSignificand); - } - - // Low three bits are round, guard, and sticky. - const roundGuardSticky = aSignificand & 0x7; - - // Shift the significand into place, and mask off the integer bit, if it's implicit. - var result = (aSignificand >> 3) & significandMask; - - // Insert the exponent and sign. - result |= @intCast(Z, aExponent) << significandBits; - result |= resultSign; - - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if (roundGuardSticky > 0x4) result += 1; - if (roundGuardSticky == 0x4) result += result & 1; - - // Restore any explicit integer bit, if it was rounded off - if (significandBits != fractionalBits) { - if ((result >> significandBits) != 0) result |= integerBit; - } - - return @bitCast(T, result); -} - -test { - _ = @import("addXf3_test.zig"); -} diff --git a/lib/compiler_rt/addXf3_test.zig b/lib/compiler_rt/addXf3_test.zig deleted file mode 100644 index f38c9d6018..0000000000 --- a/lib/compiler_rt/addXf3_test.zig +++ /dev/null @@ -1,157 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c -// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c - -const std = @import("std"); -const math = std.math; -const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); - -const __addtf3 = @import("addXf3.zig").__addtf3; - -fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __addtf3(a, b); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expected_hi and lo == expected_lo) { - return; - } - // test other possible NaN representation (signal NaN) - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailed; -} - -test "addtf3" { - try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN + any = NaN - try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // inf + inf = inf - try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); - - // inf + any = inf - try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); - - // any + any - try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); - try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); -} - -const __subtf3 = @import("addXf3.zig").__subtf3; - -fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __subtf3(a, b); - - const rep = @bitCast(u128, x); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expected_hi and lo == expected_lo) { - return; - } - // test other possible NaN representation (signal NaN) - else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return; - } - } - - return error.TestFailed; -} - -test "subtf3" { - // qNaN - any = qNaN - try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN + any = NaN - try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // inf - any = inf - try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); - - // any + any - try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); - try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); -} - -const __addxf3 = @import("addXf3.zig").__addxf3; -const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); - -fn test__addxf3(a: f80, b: f80, expected: u80) !void { - const x = __addxf3(a, b); - const rep = @bitCast(u80, x); - - if (rep == expected) - return; - - if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) - return; // We don't currently test NaN payload propagation - - return error.TestFailed; -} - -test "addxf3" { - // NaN + any = NaN - try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - - // any + NaN = NaN - try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); - try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); - - // NaN + inf = NaN - try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); - - // inf + NaN = NaN - try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); - - // inf + inf = inf - try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); - - // inf + -inf = NaN - try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); - - // -inf + inf = NaN - try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); - - // inf + any = inf - try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); - - // any + inf = inf - try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); - - // any + any - try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); - try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up - try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact - - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up - try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact - try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact - try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact -} diff --git a/lib/compiler_rt/adddf3.zig b/lib/compiler_rt/adddf3.zig new file mode 100644 index 0000000000..1b511f78a4 --- /dev/null +++ b/lib/compiler_rt/adddf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dadd, .{ .name = "__aeabi_dadd", .linkage = common.linkage }); + } else { + @export(__adddf3, .{ .name = "__adddf3", .linkage = common.linkage }); + } +} + +fn __adddf3(a: f64, b: f64) callconv(.C) f64 { + return addf3(f64, a, b); +} + +fn __aeabi_dadd(a: f64, b: f64) callconv(.AAPCS) f64 { + return addf3(f64, a, b); +} diff --git a/lib/compiler_rt/addf3.zig b/lib/compiler_rt/addf3.zig new file mode 100644 index 0000000000..7f2e368121 --- /dev/null +++ b/lib/compiler_rt/addf3.zig @@ -0,0 +1,172 @@ +const std = @import("std"); +const math = std.math; +const common = @import("./common.zig"); +const normalize = common.normalize; + +/// 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 { + const bits = @typeInfo(T).Float.bits; + const Z = std.meta.Int(.unsigned, bits); + const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); + + const typeWidth = bits; + const significandBits = math.floatMantissaBits(T); + const fractionalBits = math.floatFractionalBits(T); + const exponentBits = math.floatExponentBits(T); + + const signBit = (@as(Z, 1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + + const integerBit = (@as(Z, 1) << fractionalBits); + const quietBit = integerBit >> 1; + const significandMask = (@as(Z, 1) << significandBits) - 1; + + const absMask = signBit - 1; + const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; + + var aRep = @bitCast(Z, a); + var bRep = @bitCast(Z, b); + const aAbs = aRep & absMask; + const bAbs = bRep & absMask; + + const infRep = @bitCast(Z, math.inf(T)); + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or + bAbs -% @as(Z, 1) >= infRep - @as(Z, 1)) + { + // NaN + anything = qNaN + if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { + return @bitCast(T, qnanRep); + } + // +/-infinity + anything remaining = +/- infinity + else { + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (aAbs == 0) { + // but we need to get the sign right for zero + zero + if (bAbs == 0) { + return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); + } else { + return b; + } + } + + // anything + zero = anything + if (bAbs == 0) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); + var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); + var aSignificand = aRep & significandMask; + var bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(T, &aSignificand); + if (bExponent == 0) bExponent = normalize(T, &bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const resultSign = aRep & signBit; + const subtraction = (aRep ^ bRep) & signBit != 0; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | integerBit) << 3; + bSignificand = (bSignificand | integerBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const @"align" = @intCast(u32, aExponent - bExponent); + if (@"align" != 0) { + if (@"align" < typeWidth) { + const sticky = if (bSignificand << @intCast(S, typeWidth - @"align") != 0) @as(Z, 1) else 0; + bSignificand = (bSignificand >> @truncate(S, @"align")) | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + if (subtraction) { + aSignificand -= bSignificand; + // If a == -b, return +zero. + if (aSignificand == 0) return @bitCast(T, @as(Z, 0)); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < integerBit << 3) { + const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); + aSignificand <<= @intCast(S, shift); + aExponent -= shift; + } + } else { // addition + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & (integerBit << 4) != 0) { + const sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal; the exponent and round/sticky bits are zero. + // All we need to do is shift the significand and apply the correct sign. + aSignificand >>= @intCast(S, 4 - aExponent); + return @bitCast(T, resultSign | aSignificand); + } + + // Low three bits are round, guard, and sticky. + const roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the integer bit, if it's implicit. + var result = (aSignificand >> 3) & significandMask; + + // Insert the exponent and sign. + result |= @intCast(Z, aExponent) << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result += 1; + if (roundGuardSticky == 0x4) result += result & 1; + + // Restore any explicit integer bit, if it was rounded off + if (significandBits != fractionalBits) { + if ((result >> significandBits) != 0) result |= integerBit; + } + + return @bitCast(T, result); +} + +test { + _ = @import("addf3_test.zig"); +} diff --git a/lib/compiler_rt/addf3_test.zig b/lib/compiler_rt/addf3_test.zig new file mode 100644 index 0000000000..cd3f3ab89c --- /dev/null +++ b/lib/compiler_rt/addf3_test.zig @@ -0,0 +1,157 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c + +const std = @import("std"); +const math = std.math; +const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); + +const __addtf3 = @import("addf3.zig").__addtf3; + +fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __addtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailed; +} + +test "addtf3" { + try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + try test__addtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf + inf = inf + try test__addtf3(math.inf(f128), math.inf(f128), 0x7fff000000000000, 0x0); + + // inf + any = inf + try test__addtf3(math.inf(f128), 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + try test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); + try test__addtf3(0x1.edcba52449872455634654321fp-1, 0x1.23456734245345543849abcdefp+5, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); +} + +const __subtf3 = @import("addf3.zig").__subtf3; + +fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __subtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + return error.TestFailed; +} + +test "subtf3" { + // qNaN - any = qNaN + try test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + try test__subtf3(@bitCast(f128, (@as(u128, 0x7fff000000000000) << 64) | @as(u128, 0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf - any = inf + try test__subtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + try test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); + try test__subtf3(0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x1.234567829a3bcdef5678ade36734p+5, 0xc0041b8af1915166, 0xa44a7bca780a166c); +} + +const __addxf3 = @import("addf3.zig").__addxf3; +const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); + +fn test__addxf3(a: f80, b: f80, expected: u80) !void { + const x = __addxf3(a, b); + const rep = @bitCast(u80, x); + + if (rep == expected) + return; + + if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) + return; // We don't currently test NaN payload propagation + + return error.TestFailed; +} + +test "addxf3" { + // NaN + any = NaN + try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + try test__addxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + + // any + NaN = NaN + try test__addxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); + try test__addxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); + + // NaN + inf = NaN + try test__addxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); + + // inf + NaN = NaN + try test__addxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); + + // inf + inf = inf + try test__addxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); + + // inf + -inf = NaN + try test__addxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, qnan80)); + + // -inf + inf = NaN + try test__addxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, qnan80)); + + // inf + any = inf + try test__addxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); + + // any + inf = inf + try test__addxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, math.inf(f80))); + + // any + any + try test__addxf3(0x1.23456789abcdp+5, 0x1.dcba987654321p+5, 0x4005_BFFFFFFFFFFFC400); + try test__addxf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x4004_957E_4AE4_5ABC_B0F3); + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.0p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffep+0, 0x0.0p0, 0x3FFF_FFFFFFFFFFFFFFFF); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.4p-63, 0x3FFF_FFFFFFFFFFFFFFFF); // round down + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.8p-63, 0x4000_8000000000000000); // round up to even + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x1.cp-63, 0x4000_8000000000000000); // round up + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.0p-63, 0x4000_8000000000000000); // exact + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x2.1p-63, 0x4000_8000000000000000); // round down + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.0p-63, 0x4000_8000000000000000); // round down to even + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x3.1p-63, 0x4000_8000000000000001); // round up + try test__addxf3(0x1.ffff_ffff_ffff_fffcp+0, 0x4.0p-63, 0x4000_8000000000000001); // exact + + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.0p-63, 0x3FFF_8800000000000000); // exact + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.7p-63, 0x3FFF_8800000000000000); // round down + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.8p-63, 0x3FFF_8800000000000000); // round down to even + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x1.9p-63, 0x3FFF_8800000000000001); // round up + try test__addxf3(0x1.0fff_ffff_ffff_fffep+0, 0x2.0p-63, 0x3FFF_8800000000000001); // exact + try test__addxf3(0x0.ffff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_7FFFFFFFFFFFFFFF); // exact + try test__addxf3(0x0.1fff_ffff_ffff_fffcp-16382, 0x0.0000_0000_0000_0002p-16382, 0x0000_0FFFFFFFFFFFFFFF); // exact +} diff --git a/lib/compiler_rt/addsf3.zig b/lib/compiler_rt/addsf3.zig new file mode 100644 index 0000000000..83f8285371 --- /dev/null +++ b/lib/compiler_rt/addsf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fadd, .{ .name = "__aeabi_fadd", .linkage = common.linkage }); + } else { + @export(__addsf3, .{ .name = "__addsf3", .linkage = common.linkage }); + } +} + +fn __addsf3(a: f32, b: f32) callconv(.C) f32 { + return addf3(f32, a, b); +} + +fn __aeabi_fadd(a: f32, b: f32) callconv(.AAPCS) f32 { + return addf3(f32, a, b); +} diff --git a/lib/compiler_rt/addtf3.zig b/lib/compiler_rt/addtf3.zig new file mode 100644 index 0000000000..40a6e6c8b7 --- /dev/null +++ b/lib/compiler_rt/addtf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__addkf3, .{ .name = "__addkf3", .linkage = common.linkage }); + } else { + @export(__addtf3, .{ .name = "__addtf3", .linkage = common.linkage }); + } +} + +fn __addtf3(a: f128, b: f128) callconv(.C) f128 { + return addf3(f128, a, b); +} + +fn __addkf3(a: f128, b: f128) callconv(.C) f128 { + return addf3(f128, a, b); +} diff --git a/lib/compiler_rt/addxf3.zig b/lib/compiler_rt/addxf3.zig new file mode 100644 index 0000000000..67e7dd8491 --- /dev/null +++ b/lib/compiler_rt/addxf3.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const addf3 = @import("./addf3.zig").addf3; + +pub const panic = common.panic; + +comptime { + @export(__addxf3, .{ .name = "__addxf3", .linkage = common.linkage }); +} + +fn __addxf3(a: f80, b: f80) callconv(.C) f80 { + return addf3(f80, a, b); +} diff --git a/lib/compiler_rt/cmpdf2.zig b/lib/compiler_rt/cmpdf2.zig new file mode 100644 index 0000000000..f1661731fb --- /dev/null +++ b/lib/compiler_rt/cmpdf2.zig @@ -0,0 +1,68 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = common.linkage }); + @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = common.linkage }); + @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = common.linkage }); + } else { + @export(__eqdf2, .{ .name = "__eqdf2", .linkage = common.linkage }); + @export(__nedf2, .{ .name = "__nedf2", .linkage = common.linkage }); + @export(__ledf2, .{ .name = "__ledf2", .linkage = common.linkage }); + @export(__cmpdf2, .{ .name = "__cmpdf2", .linkage = common.linkage }); + @export(__ltdf2, .{ .name = "__ltdf2", .linkage = common.linkage }); + } +} + +/// "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 @enumToInt(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." +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. +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. +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." +fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { + return __cmpdf2(a, b); +} + +fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Equal); +} + +fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) == .Less); +} + +fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater); +} diff --git a/lib/compiler_rt/cmpsf2.zig b/lib/compiler_rt/cmpsf2.zig new file mode 100644 index 0000000000..23be99c3f7 --- /dev/null +++ b/lib/compiler_rt/cmpsf2.zig @@ -0,0 +1,68 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = common.linkage }); + @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = common.linkage }); + @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = common.linkage }); + } else { + @export(__eqsf2, .{ .name = "__eqsf2", .linkage = common.linkage }); + @export(__nesf2, .{ .name = "__nesf2", .linkage = common.linkage }); + @export(__lesf2, .{ .name = "__lesf2", .linkage = common.linkage }); + @export(__cmpsf2, .{ .name = "__cmpsf2", .linkage = common.linkage }); + @export(__ltsf2, .{ .name = "__ltsf2", .linkage = common.linkage }); + } +} + +/// "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 @enumToInt(comparef.cmpf2(f32, 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 __lesf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(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. +fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(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. +fn __nesf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +/// "These functions return a value less than zero if neither argument is NaN, and a +/// is strictly less than b." +fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { + return __cmpsf2(a, b); +} + +fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Equal); +} + +fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Less); +} + +fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) != .Greater); +} diff --git a/lib/compiler_rt/cmptf2.zig b/lib/compiler_rt/cmptf2.zig new file mode 100644 index 0000000000..86dc68ad56 --- /dev/null +++ b/lib/compiler_rt/cmptf2.zig @@ -0,0 +1,73 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__eqkf2, .{ .name = "__eqkf2", .linkage = common.linkage }); + @export(__nekf2, .{ .name = "__nekf2", .linkage = common.linkage }); + @export(__ltkf2, .{ .name = "__ltkf2", .linkage = common.linkage }); + @export(__lekf2, .{ .name = "__lekf2", .linkage = common.linkage }); + } else { + @export(__eqtf2, .{ .name = "__eqtf2", .linkage = common.linkage }); + @export(__netf2, .{ .name = "__netf2", .linkage = common.linkage }); + @export(__letf2, .{ .name = "__letf2", .linkage = common.linkage }); + @export(__cmptf2, .{ .name = "__cmptf2", .linkage = common.linkage }); + @export(__lttf2, .{ .name = "__lttf2", .linkage = common.linkage }); + } +} + +/// "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 @enumToInt(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); +} + +fn __eqkf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __nekf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} + +fn __lekf2(a: f128, b: f128) callconv(.C) i32 { + return __cmptf2(a, b); +} diff --git a/lib/compiler_rt/cmpxf2.zig b/lib/compiler_rt/cmpxf2.zig new file mode 100644 index 0000000000..7286316f99 --- /dev/null +++ b/lib/compiler_rt/cmpxf2.zig @@ -0,0 +1,50 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + @export(__eqxf2, .{ .name = "__eqxf2", .linkage = common.linkage }); + @export(__nexf2, .{ .name = "__nexf2", .linkage = common.linkage }); + @export(__lexf2, .{ .name = "__lexf2", .linkage = common.linkage }); + @export(__cmpxf2, .{ .name = "__cmpxf2", .linkage = common.linkage }); + @export(__ltxf2, .{ .name = "__ltxf2", .linkage = common.linkage }); +} + +/// "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 @enumToInt(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/common.zig b/lib/compiler_rt/common.zig index 7e9bdf81c8..196dc33024 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -3,8 +3,14 @@ const builtin = @import("builtin"); const math = std.math; const is_test = builtin.is_test; +pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; +pub const want_aeabi = builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb(); +pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); +pub const want_msvc_abi = builtin.abi == .msvc; +pub const want_gnu_abi = builtin.abi.isGnu(); + // Avoid dragging in the runtime safety mechanisms into this .o file, -// unless we're trying to test this file. +// unless we're trying to test compiler-rt. pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { _ = error_return_trace; @setCold(true); @@ -15,8 +21,13 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore } } +/// AArch64 is the only ABI (at the moment) to support f16 arguments without the +/// need for extending them to wider fp types. +/// TODO remove this; do this type selection in the language rather than +/// here in compiler-rt. +pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16; + pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { - @setRuntimeSafety(is_test); switch (Z) { u16 => { // 16x16 --> 32 bit multiply @@ -130,15 +141,11 @@ pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { } } -// TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T).Float.bits)) i32 { - const bits = @typeInfo(T).Float.bits; - const Z = std.meta.Int(.unsigned, bits); - const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); - const fractionalBits = math.floatFractionalBits(T); - const integerBit = @as(Z, 1) << fractionalBits; + const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); + const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); - const shift = @clz(std.meta.Int(.unsigned, bits), significand.*) - @clz(Z, integerBit); - significand.* <<= @intCast(S, shift); + const shift = @clz(Z, significand.*) - @clz(Z, integerBit); + significand.* <<= @intCast(std.math.Log2Int(Z), shift); return @as(i32, 1) - shift; } diff --git a/lib/compiler_rt/compareXf2.zig b/lib/compiler_rt/compareXf2.zig deleted file mode 100644 index d21a6777e4..0000000000 --- a/lib/compiler_rt/compareXf2.zig +++ /dev/null @@ -1,440 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c - -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const arch = builtin.cpu.arch; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__lesf2, .{ .name = "__lesf2", .linkage = linkage }); - @export(__ledf2, .{ .name = "__ledf2", .linkage = linkage }); - @export(__letf2, .{ .name = "__letf2", .linkage = linkage }); - @export(__lexf2, .{ .name = "__lexf2", .linkage = linkage }); - - @export(__gesf2, .{ .name = "__gesf2", .linkage = linkage }); - @export(__gedf2, .{ .name = "__gedf2", .linkage = linkage }); - @export(__getf2, .{ .name = "__getf2", .linkage = linkage }); - @export(__gexf2, .{ .name = "__gexf2", .linkage = linkage }); - - @export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage }); - @export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage }); - @export(__eqxf2, .{ .name = "__eqxf2", .linkage = linkage }); - - @export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage }); - @export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage }); - @export(__ltxf2, .{ .name = "__ltxf2", .linkage = linkage }); - - @export(__nesf2, .{ .name = "__nesf2", .linkage = linkage }); - @export(__nedf2, .{ .name = "__nedf2", .linkage = linkage }); - @export(__nexf2, .{ .name = "__nexf2", .linkage = linkage }); - - @export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage }); - @export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage }); - @export(__gtxf2, .{ .name = "__gtxf2", .linkage = linkage }); - - @export(__unordsf2, .{ .name = "__unordsf2", .linkage = linkage }); - @export(__unorddf2, .{ .name = "__unorddf2", .linkage = linkage }); - @export(__unordtf2, .{ .name = "__unordtf2", .linkage = linkage }); - - if (!is_test) { - @export(__cmpsf2, .{ .name = "__cmpsf2", .linkage = linkage }); - @export(__cmpdf2, .{ .name = "__cmpdf2", .linkage = linkage }); - @export(__cmptf2, .{ .name = "__cmptf2", .linkage = linkage }); - @export(__eqtf2, .{ .name = "__eqtf2", .linkage = linkage }); - @export(__lttf2, .{ .name = "__lttf2", .linkage = linkage }); - @export(__gttf2, .{ .name = "__gttf2", .linkage = linkage }); - @export(__netf2, .{ .name = "__netf2", .linkage = linkage }); - - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage }); - @export(__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage }); - @export(__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage }); - @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage }); - @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage }); - @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage }); - - @export(__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage }); - @export(__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage }); - @export(__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage }); - @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage }); - @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage }); - @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__eqkf2, .{ .name = "__eqkf2", .linkage = linkage }); - @export(__nekf2, .{ .name = "__nekf2", .linkage = linkage }); - @export(__gekf2, .{ .name = "__gekf2", .linkage = linkage }); - @export(__ltkf2, .{ .name = "__ltkf2", .linkage = linkage }); - @export(__lekf2, .{ .name = "__lekf2", .linkage = linkage }); - @export(__gtkf2, .{ .name = "__gtkf2", .linkage = linkage }); - @export(__unordkf2, .{ .name = "__unordkf2", .linkage = linkage }); - } - } -} - -const LE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, - - const Unordered: LE = .Greater; -}; - -const GE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, - - const Unordered: GE = .Less; -}; - -pub inline fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { - @setRuntimeSafety(builtin.is_test); - - const bits = @typeInfo(T).Float.bits; - const srep_t = std.meta.Int(.signed, bits); - const rep_t = std.meta.Int(.unsigned, bits); - - const significandBits = std.math.floatMantissaBits(T); - const exponentBits = std.math.floatExponentBits(T); - const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); - const absMask = signBit - 1; - const infT = comptime std.math.inf(T); - const infRep = @bitCast(rep_t, infT); - - const aInt = @bitCast(srep_t, a); - const bInt = @bitCast(srep_t, b); - const aAbs = @bitCast(rep_t, aInt) & absMask; - const bAbs = @bitCast(rep_t, bInt) & absMask; - - // If either a or b is NaN, they are unordered. - if (aAbs > infRep or bAbs > infRep) return RT.Unordered; - - // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) return .Equal; - - // 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; - } else if (aInt == bInt) { - return .Equal; - } else return .Greater; - } 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; - } else if (aInt == bInt) { - return .Equal; - } else return .Greater; - } -} - -pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { - @setRuntimeSafety(builtin.is_test); - - const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); - - const significandBits = std.math.floatMantissaBits(T); - const exponentBits = std.math.floatExponentBits(T); - const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); - const absMask = signBit - 1; - const infRep = @bitCast(rep_t, std.math.inf(T)); - - const aAbs: rep_t = @bitCast(rep_t, a) & absMask; - const bAbs: rep_t = @bitCast(rep_t, b) & absMask; - - return @boolToInt(aAbs > infRep or bAbs > infRep); -} - -// Comparison between f32 - -pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f32, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f32, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __cmpsf2(a: f32, b: f32) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); -} - -pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); -} - -pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); -} - -pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }); -} - -pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }); -} - -// Comparison between f64 - -pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f64, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f64, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __cmpdf2(a: f64, b: f64) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); -} - -pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); -} - -pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); -} - -pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }); -} - -pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }); -} - -// Comparison between f80 - -pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { - const a_rep = std.math.break_f80(a); - const b_rep = std.math.break_f80(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 (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(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 (@bitCast(i16, a_rep.exp) < @bitCast(i16, 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) { - return .Less; - } else { - return .Greater; - } - } -} - -pub fn __lexf2(a: f80, b: f80) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp_f80(LE, a, b); - return @bitCast(i32, float); -} - -pub fn __gexf2(a: f80, b: f80) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp_f80(GE, a, b); - return @bitCast(i32, float); -} - -pub fn __eqxf2(a: f80, b: f80) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); -} - -pub fn __ltxf2(a: f80, b: f80) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); -} - -pub fn __nexf2(a: f80, b: f80) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __lexf2, .{ a, b }); -} - -pub fn __gtxf2(a: f80, b: f80) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __gexf2, .{ a, b }); -} - -// Comparison between f128 - -pub fn __letf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f128, LE, a, b); - return @bitCast(i32, float); -} - -pub fn __getf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - const float = cmp(f128, GE, a, b); - return @bitCast(i32, float); -} - -pub fn __cmptf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __eqtf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __lttf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __netf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __gttf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); -} - -pub fn __eqkf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __nekf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __gekf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); -} - -pub fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __lekf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __letf2, .{ a, b }); -} - -pub fn __gtkf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __getf2, .{ a, b }); -} - -// Unordered comparison between f32/f64/f128 - -pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f32, a, b); -} - -pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f64, a, b); -} - -pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { - @setRuntimeSafety(builtin.is_test); - return unordcmp(f128, a, b); -} - -pub fn __unordkf2(a: f128, b: f128) callconv(.C) i32 { - return @call(.{ .modifier = .always_inline }, __unordtf2, .{ a, b }); -} - -// ARM EABI intrinsics - -pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __eqsf2, .{ a, b }) == 0); -} - -pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ltsf2, .{ a, b }) < 0); -} - -pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }) <= 0); -} - -pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }) >= 0); -} - -pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gtsf2, .{ a, b }) > 0); -} - -pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b }); -} - -pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __eqdf2, .{ a, b }) == 0); -} - -pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ltdf2, .{ a, b }) < 0); -} - -pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }) <= 0); -} - -pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }) >= 0); -} - -pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @boolToInt(@call(.{ .modifier = .always_inline }, __gtdf2, .{ a, b }) > 0); -} - -pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b }); -} - -test "comparesf2" { - _ = @import("comparesf2_test.zig"); -} -test "comparedf2" { - _ = @import("comparedf2_test.zig"); -} diff --git a/lib/compiler_rt/comparef.zig b/lib/compiler_rt/comparef.zig new file mode 100644 index 0000000000..1fb6d2dfa0 --- /dev/null +++ b/lib/compiler_rt/comparef.zig @@ -0,0 +1,118 @@ +const std = @import("std"); + +pub const LE = enum(i32) { + Less = -1, + Equal = 0, + Greater = 1, + + const Unordered: LE = .Greater; +}; + +pub const GE = enum(i32) { + Less = -1, + Equal = 0, + Greater = 1, + + const Unordered: GE = .Less; +}; + +pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { + const bits = @typeInfo(T).Float.bits; + const srep_t = std.meta.Int(.signed, bits); + const rep_t = std.meta.Int(.unsigned, bits); + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); + const absMask = signBit - 1; + const infT = comptime std.math.inf(T); + const infRep = @bitCast(rep_t, infT); + + const aInt = @bitCast(srep_t, a); + const bInt = @bitCast(srep_t, b); + const aAbs = @bitCast(rep_t, aInt) & absMask; + const bAbs = @bitCast(rep_t, bInt) & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep or bAbs > infRep) return RT.Unordered; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return .Equal; + + // 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; + } else if (aInt == bInt) { + return .Equal; + } else return .Greater; + } 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; + } else if (aInt == bInt) { + return .Equal; + } else return .Greater; + } +} + +pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { + const a_rep = std.math.break_f80(a); + const b_rep = std.math.break_f80(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 (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(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 (@bitCast(i16, a_rep.exp) < @bitCast(i16, 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) { + return .Less; + } else { + return .Greater; + } + } +} + +pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { + const rep_t = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); + + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); + const absMask = signBit - 1; + const infRep = @bitCast(rep_t, std.math.inf(T)); + + const aAbs: rep_t = @bitCast(rep_t, a) & absMask; + const bAbs: rep_t = @bitCast(rep_t, b) & absMask; + + return @boolToInt(aAbs > infRep or bAbs > infRep); +} + +test { + _ = @import("comparesf2_test.zig"); + _ = @import("comparedf2_test.zig"); +} diff --git a/lib/compiler_rt/extendXfYf2.zig b/lib/compiler_rt/extendXfYf2.zig deleted file mode 100644 index bb21e5f681..0000000000 --- a/lib/compiler_rt/extendXfYf2.zig +++ /dev/null @@ -1,148 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const arch = builtin.cpu.arch; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage }); - @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = linkage }); - @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = linkage }); - @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage }); - @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage }); - - if (!is_test) { - @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = linkage }); - - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage }); - @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = linkage }); - @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = linkage }); - } - } -} - -pub fn __extendsfdf2(a: f32) callconv(.C) f64 { - return extendXfYf2(f64, f32, @bitCast(u32, a)); -} - -pub fn __extenddftf2(a: f64) callconv(.C) f128 { - return extendXfYf2(f128, f64, @bitCast(u64, a)); -} - -pub fn __extenddfkf2(a: f64) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __extenddftf2, .{a}); -} - -pub fn __extendsftf2(a: f32) callconv(.C) f128 { - return extendXfYf2(f128, f32, @bitCast(u32, a)); -} - -pub fn __extendsfkf2(a: f32) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __extendsftf2, .{a}); -} - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -pub const F16T = if (arch.isAARCH64()) f16 else u16; - -pub fn __extendhfsf2(a: F16T) callconv(.C) f32 { - return extendXfYf2(f32, f16, @bitCast(u16, a)); -} - -pub fn __gnu_h2f_ieee(a: F16T) callconv(.C) f32 { - return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{a}); -} - -pub fn __extendhftf2(a: F16T) callconv(.C) f128 { - return extendXfYf2(f128, f16, @bitCast(u16, a)); -} - -pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, arg }); -} - -pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, arg) }); -} - -inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) dst_t { - @setRuntimeSafety(builtin.is_test); - - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); - const srcSigBits = std.math.floatMantissaBits(src_t); - const dstSigBits = std.math.floatMantissaBits(dst_t); - const DstShift = std.math.Log2Int(dst_rep_t); - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const srcBits = @bitSizeOf(src_t); - const srcExpBits = srcBits - srcSigBits - 1; - const srcInfExp = (1 << srcExpBits) - 1; - const srcExpBias = srcInfExp >> 1; - - const srcMinNormal = 1 << srcSigBits; - const srcInfinity = srcInfExp << srcSigBits; - const srcSignMask = 1 << (srcSigBits + srcExpBits); - const srcAbsMask = srcSignMask - 1; - const srcQNaN = 1 << (srcSigBits - 1); - const srcNaNCode = srcQNaN - 1; - - const dstBits = @bitSizeOf(dst_t); - const dstExpBits = dstBits - dstSigBits - 1; - const dstInfExp = (1 << dstExpBits) - 1; - const dstExpBias = dstInfExp >> 1; - - const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; - - // Break a into a sign and representation of the absolute value - const aRep: src_rep_t = @bitCast(src_rep_t, a); - const aAbs: src_rep_t = aRep & srcAbsMask; - const sign: src_rep_t = aRep & srcSignMask; - var absResult: dst_rep_t = undefined; - - if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); - absResult += (dstExpBias - srcExpBias) << dstSigBits; - } else if (aAbs >= srcInfinity) { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - absResult = dstInfExp << dstSigBits; - absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); - absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); - } else if (aAbs != 0) { - // a is denormal. - // renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - const scale: u32 = @clz(src_rep_t, aAbs) - - @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); - absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); - absResult ^= dstMinNormal; - const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; - absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; - } else { - // a is zero. - absResult = 0; - } - - // 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); - return @bitCast(dst_t, result); -} - -test { - _ = @import("extendXfYf2_test.zig"); -} diff --git a/lib/compiler_rt/extend_f80.zig b/lib/compiler_rt/extend_f80.zig deleted file mode 100644 index fe5a38fc68..0000000000 --- a/lib/compiler_rt/extend_f80.zig +++ /dev/null @@ -1,140 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const is_test = builtin.is_test; -const arch = builtin.cpu.arch; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = linkage }); - @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = linkage }); - @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = linkage }); - @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = linkage }); -} - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -const F16T = if (arch.isAARCH64()) f16 else u16; - -fn __extendhfxf2(a: F16T) callconv(.C) f80 { - return extendF80(f16, @bitCast(u16, a)); -} - -fn __extendsfxf2(a: f32) callconv(.C) f80 { - return extendF80(f32, @bitCast(u32, a)); -} - -fn __extenddfxf2(a: f64) callconv(.C) f80 { - return extendF80(f64, @bitCast(u64, a)); -} - -inline fn extendF80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { - @setRuntimeSafety(builtin.is_test); - - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const src_sig_bits = std.math.floatMantissaBits(src_t); - const dst_int_bit = 0x8000000000000000; - const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - - const dst_exp_bias = 16383; - - const src_bits = @bitSizeOf(src_t); - const src_exp_bits = src_bits - src_sig_bits - 1; - const src_inf_exp = (1 << src_exp_bits) - 1; - const src_exp_bias = src_inf_exp >> 1; - - const src_min_normal = 1 << src_sig_bits; - 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 src_qnan = 1 << (src_sig_bits - 1); - const src_nan_code = src_qnan - 1; - - var dst: std.math.F80 = undefined; - - // 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; - - if (a_abs -% src_min_normal < src_inf - src_min_normal) { - // a is a normal number. - // Extend to the destination type by shifting the significand and - // exponent into the proper position and rebiasing the exponent. - dst.exp = @intCast(u16, a_abs >> src_sig_bits); - dst.exp += dst_exp_bias - src_exp_bias; - dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); - dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers - } else if (a_abs >= src_inf) { - // a is NaN or infinity. - // Conjure the result by beginning with infinity, then setting the qNaN - // bit (if needed) and right-aligning the rest of the trailing NaN - // payload field. - dst.exp = 0x7fff; - dst.fraction = dst_int_bit; - dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); - dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); - } else if (a_abs != 0) { - // a is denormal. - // renormalize the significand and clear the leading bit, then insert - // the correct adjusted exponent in the destination type. - const scale: u16 = @clz(src_rep_t, a_abs) - - @clz(src_rep_t, @as(src_rep_t, src_min_normal)); - - dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); - dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers - dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); - dst.exp ^= 1; - dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; - } else { - // a is zero. - dst.exp = 0; - dst.fraction = 0; - } - - dst.exp |= sign; - return std.math.make_f80(dst); -} - -fn __extendxftf2(a: f80) callconv(.C) f128 { - @setRuntimeSafety(builtin.is_test); - - 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); - - const dst_min_normal = @as(u128, 1) << dst_sig_bits; - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.break_f80(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 - // renormalize the significand and clear the leading bit and integer part, - // then insert the correct adjusted exponent in the destination type. - const scale: u32 = @clz(u64, a_rep.fraction); - abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); - abs_result ^= dst_min_normal; - abs_result |= @as(u128, scale + 1) << dst_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(f128, result); -} diff --git a/lib/compiler_rt/extenddftf2.zig b/lib/compiler_rt/extenddftf2.zig new file mode 100644 index 0000000000..c957d64a63 --- /dev/null +++ b/lib/compiler_rt/extenddftf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = common.linkage }); + } else { + @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = common.linkage }); + } +} + +fn __extenddftf2(a: f64) callconv(.C) f128 { + return extendf(f128, f64, @bitCast(u64, a)); +} + +fn __extenddfkf2(a: f64) callconv(.C) f128 { + return extendf(f128, f64, @bitCast(u64, a)); +} diff --git a/lib/compiler_rt/extenddfxf2.zig b/lib/compiler_rt/extenddfxf2.zig new file mode 100644 index 0000000000..e76b2fc038 --- /dev/null +++ b/lib/compiler_rt/extenddfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extenddfxf2, .{ .name = "__extenddfxf2", .linkage = common.linkage }); +} + +fn __extenddfxf2(a: f64) callconv(.C) f80 { + return extend_f80(f64, @bitCast(u64, a)); +} diff --git a/lib/compiler_rt/extendf.zig b/lib/compiler_rt/extendf.zig new file mode 100644 index 0000000000..15fa1ce0e8 --- /dev/null +++ b/lib/compiler_rt/extendf.zig @@ -0,0 +1,142 @@ +const std = @import("std"); + +pub inline fn extendf( + comptime dst_t: type, + comptime src_t: type, + a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits), +) dst_t { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); + const srcSigBits = std.math.floatMantissaBits(src_t); + const dstSigBits = std.math.floatMantissaBits(dst_t); + const DstShift = std.math.Log2Int(dst_rep_t); + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const srcBits = @bitSizeOf(src_t); + const srcExpBits = srcBits - srcSigBits - 1; + const srcInfExp = (1 << srcExpBits) - 1; + const srcExpBias = srcInfExp >> 1; + + const srcMinNormal = 1 << srcSigBits; + const srcInfinity = srcInfExp << srcSigBits; + const srcSignMask = 1 << (srcSigBits + srcExpBits); + const srcAbsMask = srcSignMask - 1; + const srcQNaN = 1 << (srcSigBits - 1); + const srcNaNCode = srcQNaN - 1; + + const dstBits = @bitSizeOf(dst_t); + const dstExpBits = dstBits - dstSigBits - 1; + const dstInfExp = (1 << dstExpBits) - 1; + const dstExpBias = dstInfExp >> 1; + + const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; + + // Break a into a sign and representation of the absolute value + const aRep: src_rep_t = @bitCast(src_rep_t, a); + const aAbs: src_rep_t = aRep & srcAbsMask; + const sign: src_rep_t = aRep & srcSignMask; + var absResult: dst_rep_t = undefined; + + if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + absResult = @as(dst_rep_t, aAbs) << (dstSigBits - srcSigBits); + absResult += (dstExpBias - srcExpBias) << dstSigBits; + } else if (aAbs >= srcInfinity) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + absResult = dstInfExp << dstSigBits; + absResult |= @as(dst_rep_t, aAbs & srcQNaN) << (dstSigBits - srcSigBits); + absResult |= @as(dst_rep_t, aAbs & srcNaNCode) << (dstSigBits - srcSigBits); + } else if (aAbs != 0) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const scale: u32 = @clz(src_rep_t, aAbs) - + @clz(src_rep_t, @as(src_rep_t, srcMinNormal)); + absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); + absResult ^= dstMinNormal; + const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; + absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits; + } else { + // a is zero. + absResult = 0; + } + + // 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); + return @bitCast(dst_t, result); +} + +pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits)) f80 { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const src_sig_bits = std.math.floatMantissaBits(src_t); + const dst_int_bit = 0x8000000000000000; + const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + + const dst_exp_bias = 16383; + + const src_bits = @bitSizeOf(src_t); + const src_exp_bits = src_bits - src_sig_bits - 1; + const src_inf_exp = (1 << src_exp_bits) - 1; + const src_exp_bias = src_inf_exp >> 1; + + const src_min_normal = 1 << src_sig_bits; + 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 src_qnan = 1 << (src_sig_bits - 1); + const src_nan_code = src_qnan - 1; + + var dst: std.math.F80 = undefined; + + // 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; + + if (a_abs -% src_min_normal < src_inf - src_min_normal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + dst.exp = @intCast(u16, a_abs >> src_sig_bits); + dst.exp += dst_exp_bias - src_exp_bias; + dst.fraction = @as(u64, a_abs) << (dst_sig_bits - src_sig_bits); + dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers + } else if (a_abs >= src_inf) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + dst.exp = 0x7fff; + dst.fraction = dst_int_bit; + dst.fraction |= @as(u64, a_abs & src_qnan) << (dst_sig_bits - src_sig_bits); + dst.fraction |= @as(u64, a_abs & src_nan_code) << (dst_sig_bits - src_sig_bits); + } else if (a_abs != 0) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const scale: u16 = @clz(src_rep_t, a_abs) - + @clz(src_rep_t, @as(src_rep_t, src_min_normal)); + + dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); + dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers + dst.exp = @truncate(u16, a_abs >> @intCast(u4, src_sig_bits - scale)); + dst.exp ^= 1; + dst.exp |= dst_exp_bias - src_exp_bias - scale + 1; + } else { + // a is zero. + dst.exp = 0; + dst.fraction = 0; + } + + dst.exp |= sign; + return std.math.make_f80(dst); +} + +test { + _ = @import("extendXfYf2_test.zig"); +} diff --git a/lib/compiler_rt/extendhfsf2.zig b/lib/compiler_rt/extendhfsf2.zig new file mode 100644 index 0000000000..6ad4ff37df --- /dev/null +++ b/lib/compiler_rt/extendhfsf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_gnu_abi) { + @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = common.linkage }); + } else if (common.want_aeabi) { + @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage }); + } else { + @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage }); + } +} + +fn __extendhfsf2(a: common.F16T) callconv(.C) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} + +fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} + +fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 { + return extendf(f32, f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendhftf2.zig b/lib/compiler_rt/extendhftf2.zig new file mode 100644 index 0000000000..a0c8eb5a1e --- /dev/null +++ b/lib/compiler_rt/extendhftf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + @export(__extendhftf2, .{ .name = "__extendhftf2", .linkage = common.linkage }); +} + +fn __extendhftf2(a: common.F16T) callconv(.C) f128 { + return extendf(f128, f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendhfxf2.zig b/lib/compiler_rt/extendhfxf2.zig new file mode 100644 index 0000000000..e509f96575 --- /dev/null +++ b/lib/compiler_rt/extendhfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extendhfxf2, .{ .name = "__extendhfxf2", .linkage = common.linkage }); +} + +fn __extendhfxf2(a: common.F16T) callconv(.C) f80 { + return extend_f80(f16, @bitCast(u16, a)); +} diff --git a/lib/compiler_rt/extendsfdf2.zig b/lib/compiler_rt/extendsfdf2.zig new file mode 100644 index 0000000000..7fd69f6c22 --- /dev/null +++ b/lib/compiler_rt/extendsfdf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = common.linkage }); + } else { + @export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = common.linkage }); + } +} + +fn __extendsfdf2(a: f32) callconv(.C) f64 { + return extendf(f64, f32, @bitCast(u32, a)); +} + +fn __aeabi_f2d(a: f32) callconv(.AAPCS) f64 { + return extendf(f64, f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendsftf2.zig b/lib/compiler_rt/extendsftf2.zig new file mode 100644 index 0000000000..8b496783c8 --- /dev/null +++ b/lib/compiler_rt/extendsftf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const extendf = @import("./extendf.zig").extendf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = common.linkage }); + } else { + @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = common.linkage }); + } +} + +fn __extendsftf2(a: f32) callconv(.C) f128 { + return extendf(f128, f32, @bitCast(u32, a)); +} + +fn __extendsfkf2(a: f32) callconv(.C) f128 { + return extendf(f128, f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendsfxf2.zig b/lib/compiler_rt/extendsfxf2.zig new file mode 100644 index 0000000000..41bb5ace85 --- /dev/null +++ b/lib/compiler_rt/extendsfxf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const extend_f80 = @import("./extendf.zig").extend_f80; + +pub const panic = common.panic; + +comptime { + @export(__extendsfxf2, .{ .name = "__extendsfxf2", .linkage = common.linkage }); +} + +fn __extendsfxf2(a: f32) callconv(.C) f80 { + return extend_f80(f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/extendxftf2.zig b/lib/compiler_rt/extendxftf2.zig new file mode 100644 index 0000000000..bb5d6a377b --- /dev/null +++ b/lib/compiler_rt/extendxftf2.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__extendxftf2, .{ .name = "__extendxftf2", .linkage = common.linkage }); +} + +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); + + const dst_min_normal = @as(u128, 1) << dst_sig_bits; + + // Break a into a sign and representation of the absolute value + var a_rep = std.math.break_f80(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 + // renormalize the significand and clear the leading bit and integer part, + // then insert the correct adjusted exponent in the destination type. + const scale: u32 = @clz(u64, a_rep.fraction); + abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); + abs_result ^= dst_min_normal; + abs_result |= @as(u128, scale + 1) << dst_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(f128, result); +} diff --git a/lib/compiler_rt/fixXfYi.zig b/lib/compiler_rt/fixXfYi.zig deleted file mode 100644 index c568bba366..0000000000 --- a/lib/compiler_rt/fixXfYi.zig +++ /dev/null @@ -1,312 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const math = std.math; -const Log2Int = math.Log2Int; -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - // Float -> Integral Conversion - - // Conversion from f32 - @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = linkage }); - @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = linkage }); - - @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = linkage }); - @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = linkage }); - - @export(__fixsfti, .{ .name = "__fixsfti", .linkage = linkage }); - @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = linkage }); - - // Conversion from f64 - @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = linkage }); - @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = linkage }); - - @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = linkage }); - @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = linkage }); - - @export(__fixdfti, .{ .name = "__fixdfti", .linkage = linkage }); - @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = linkage }); - - // Conversion from f80 - @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = linkage }); - @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = linkage }); - - @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = linkage }); - @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = linkage }); - - @export(__fixxfti, .{ .name = "__fixxfti", .linkage = linkage }); - @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = linkage }); - - // Conversion from f128 - @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = linkage }); - @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = linkage }); - - @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = linkage }); - @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = linkage }); - - @export(__fixtfti, .{ .name = "__fixtfti", .linkage = linkage }); - @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = linkage }); - - if (!is_test) { - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = linkage }); - @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = linkage }); - - @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = linkage }); - @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = linkage }); - - @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = linkage }); - - @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = linkage }); - - @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = linkage }); - @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = linkage }); - @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = linkage }); - @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = linkage }); - @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = linkage }); - } - } -} - -pub inline fn fixXfYi(comptime I: type, a: anytype) I { - @setRuntimeSafety(is_test); - - const F = @TypeOf(a); - const float_bits = @typeInfo(F).Float.bits; - const int_bits = @typeInfo(I).Int.bits; - const rep_t = std.meta.Int(.unsigned, float_bits); - const sig_bits = math.floatMantissaBits(F); - const exp_bits = math.floatExponentBits(F); - const fractional_bits = math.floatFractionalBits(F); - - const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; - const max_exp = (1 << (exp_bits - 1)); - const exp_bias = max_exp - 1; - const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; - - // Break a into sign, exponent, significand - const a_rep: rep_t = @bitCast(rep_t, a); - const negative = (a_rep >> (float_bits - 1)) != 0; - const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; - const significand: rep_t = (a_rep & sig_mask) | implicit_bit; - - // If the exponent is negative, the result rounds to zero. - if (exponent < 0) return 0; - - // If the value is too large for the integer type, saturate. - switch (@typeInfo(I).Int.signedness) { - .unsigned => { - if (negative) return 0; - if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); - }, - .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { - return if (negative) math.minInt(I) else math.maxInt(I); - }, - } - - // If 0 <= exponent < sig_bits, right shift to get the result. - // Otherwise, shift left. - var result: I = undefined; - if (exponent < fractional_bits) { - result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); - } else { - result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); - } - - if ((@typeInfo(I).Int.signedness == .signed) and negative) - return ~result +% 1; - return result; -} - -// Conversion from f16 - -pub fn __fixhfsi(a: f16) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunshfsi(a: f16) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixhfdi(a: f16) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunshfdi(a: f16) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixhfti(a: f16) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunshfti(a: f16) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f32 - -pub fn __fixsfsi(a: f32) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunssfsi(a: f32) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixsfdi(a: f32) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunssfdi(a: f32) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixsfti(a: f32) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunssfti(a: f32) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f64 - -pub fn __fixdfsi(a: f64) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunsdfsi(a: f64) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixdfdi(a: f64) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunsdfdi(a: f64) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixdfti(a: f64) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunsdfti(a: f64) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f80 - -pub fn __fixxfsi(a: f80) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixunsxfsi(a: f80) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixxfdi(a: f80) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixunsxfdi(a: f80) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixxfti(a: f80) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunsxfti(a: f80) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f128 - -pub fn __fixtfsi(a: f128) callconv(.C) i32 { - return fixXfYi(i32, a); -} - -pub fn __fixkfsi(a: f128) callconv(.C) i32 { - return __fixtfsi(a); -} - -pub fn __fixunstfsi(a: f128) callconv(.C) u32 { - return fixXfYi(u32, a); -} - -pub fn __fixunskfsi(a: f128) callconv(.C) u32 { - return @call(.{ .modifier = .always_inline }, __fixunstfsi, .{a}); -} - -pub fn __fixtfdi(a: f128) callconv(.C) i64 { - return fixXfYi(i64, a); -} - -pub fn __fixkfdi(a: f128) callconv(.C) i64 { - return @call(.{ .modifier = .always_inline }, __fixtfdi, .{a}); -} - -pub fn __fixunstfdi(a: f128) callconv(.C) u64 { - return fixXfYi(u64, a); -} - -pub fn __fixunskfdi(a: f128) callconv(.C) u64 { - return @call(.{ .modifier = .always_inline }, __fixunstfdi, .{a}); -} - -pub fn __fixtfti(a: f128) callconv(.C) i128 { - return fixXfYi(i128, a); -} - -pub fn __fixunstfti(a: f128) callconv(.C) u128 { - return fixXfYi(u128, a); -} - -// Conversion from f32 - -pub fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { - return fixXfYi(i32, a); -} - -pub fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { - return fixXfYi(u32, a); -} - -pub fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { - return fixXfYi(i64, a); -} - -pub fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { - return fixXfYi(u64, a); -} - -// Conversion from f64 - -pub fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { - return fixXfYi(i32, a); -} - -pub fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { - return fixXfYi(u32, a); -} - -pub fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { - return fixXfYi(i64, a); -} - -pub fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { - return fixXfYi(u64, a); -} - -test { - _ = @import("fixXfYi_test.zig"); -} diff --git a/lib/compiler_rt/fixXfYi_test.zig b/lib/compiler_rt/fixXfYi_test.zig deleted file mode 100644 index 00ed455609..0000000000 --- a/lib/compiler_rt/fixXfYi_test.zig +++ /dev/null @@ -1,948 +0,0 @@ -const std = @import("std"); -const testing = std.testing; -const math = std.math; -const fixXfYi = @import("fixXfYi.zig").fixXfYi; - -// Conversion from f32 -const __fixsfsi = @import("fixXfYi.zig").__fixsfsi; -const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi; -const __fixsfdi = @import("fixXfYi.zig").__fixsfdi; -const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi; -const __fixsfti = @import("fixXfYi.zig").__fixsfti; -const __fixunssfti = @import("fixXfYi.zig").__fixunssfti; - -// Conversion from f64 -const __fixdfsi = @import("fixXfYi.zig").__fixdfsi; -const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi; -const __fixdfdi = @import("fixXfYi.zig").__fixdfdi; -const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi; -const __fixdfti = @import("fixXfYi.zig").__fixdfti; -const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti; - -// Conversion from f128 -const __fixtfsi = @import("fixXfYi.zig").__fixtfsi; -const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi; -const __fixtfdi = @import("fixXfYi.zig").__fixtfdi; -const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi; -const __fixtfti = @import("fixXfYi.zig").__fixtfti; -const __fixunstfti = @import("fixXfYi.zig").__fixunstfti; - -fn test__fixsfsi(a: f32, expected: i32) !void { - const x = __fixsfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunssfsi(a: f32, expected: u32) !void { - const x = __fixunssfsi(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); - try testing.expect(x == expected); -} - -fn test__fixunssfdi(a: f32, expected: u64) !void { - const x = __fixunssfdi(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); - try testing.expect(x == expected); -} - -fn test__fixunssfti(a: f32, expected: u128) !void { - const x = __fixunssfti(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__fixdfsi(a: f64, expected: i32) !void { - const x = __fixdfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunsdfsi(a: f64, expected: u32) !void { - const x = __fixunsdfsi(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); - try testing.expect(x == expected); -} - -fn test__fixunsdfdi(a: f64, expected: u64) !void { - const x = __fixunsdfdi(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); - try testing.expect(x == expected); -} - -fn test__fixunsdfti(a: f64, expected: u128) !void { - const x = __fixunsdfti(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__fixtfsi(a: f128, expected: i32) !void { - const x = __fixtfsi(a); - try testing.expect(x == expected); -} - -fn test__fixunstfsi(a: f128, expected: u32) !void { - const x = __fixunstfsi(a); - try testing.expect(x == expected); -} - -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); - try testing.expect(x == expected); -} - -fn test__fixunstfdi(a: f128, expected: u64) !void { - const x = __fixunstfdi(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); -} - -fn test__fixunstfti(a: f128, expected: u128) !void { - const x = __fixunstfti(a); - try testing.expect(x == expected); -} - -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); - - 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); - - try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - 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); - - try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); -} - -test "fixunstfti" { - try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); - - try test__fixunstfti(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__fixunstfti(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); -} - -fn test__fixunshfti(a: f16, expected: u128) !void { - const x = fixXfYi(u128, a); - try testing.expect(x == expected); -} - -test "fixXfYi for f16" { - try test__fixunshfti(math.inf(f16), math.maxInt(u128)); - try test__fixunshfti(math.floatMax(f16), 65504); -} - -fn test__fixunsxfti(a: f80, expected: u128) !void { - const x = fixXfYi(u128, a); - try testing.expect(x == expected); -} - -test "fixXfYi 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)); -} diff --git a/lib/compiler_rt/fixdfdi.zig b/lib/compiler_rt/fixdfdi.zig new file mode 100644 index 0000000000..2c3204db65 --- /dev/null +++ b/lib/compiler_rt/fixdfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = common.linkage }); + } else { + @export(__fixdfdi, .{ .name = "__fixdfdi", .linkage = common.linkage }); + } +} + +fn __fixdfdi(a: f64) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __aeabi_d2lz(a: f64) callconv(.AAPCS) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixdfsi.zig b/lib/compiler_rt/fixdfsi.zig new file mode 100644 index 0000000000..415160f1de --- /dev/null +++ b/lib/compiler_rt/fixdfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2iz, .{ .name = "__aeabi_d2iz", .linkage = common.linkage }); + } else { + @export(__fixdfsi, .{ .name = "__fixdfsi", .linkage = common.linkage }); + } +} + +fn __fixdfsi(a: f64) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __aeabi_d2iz(a: f64) callconv(.AAPCS) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixdfti.zig b/lib/compiler_rt/fixdfti.zig new file mode 100644 index 0000000000..56ae2bbeb2 --- /dev/null +++ b/lib/compiler_rt/fixdfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixdfti, .{ .name = "__fixdfti", .linkage = common.linkage }); +} + +fn __fixdfti(a: f64) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixhfdi.zig b/lib/compiler_rt/fixhfdi.zig new file mode 100644 index 0000000000..28e871f495 --- /dev/null +++ b/lib/compiler_rt/fixhfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfdi, .{ .name = "__fixhfdi", .linkage = common.linkage }); +} + +fn __fixhfdi(a: f16) callconv(.C) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixhfsi.zig b/lib/compiler_rt/fixhfsi.zig new file mode 100644 index 0000000000..23440eea22 --- /dev/null +++ b/lib/compiler_rt/fixhfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfsi, .{ .name = "__fixhfsi", .linkage = common.linkage }); +} + +fn __fixhfsi(a: f16) callconv(.C) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixhfti.zig b/lib/compiler_rt/fixhfti.zig new file mode 100644 index 0000000000..36fc1bf607 --- /dev/null +++ b/lib/compiler_rt/fixhfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixhfti, .{ .name = "__fixhfti", .linkage = common.linkage }); +} + +fn __fixhfti(a: f16) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixsfdi.zig b/lib/compiler_rt/fixsfdi.zig new file mode 100644 index 0000000000..71b0f047e2 --- /dev/null +++ b/lib/compiler_rt/fixsfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = common.linkage }); + } else { + @export(__fixsfdi, .{ .name = "__fixsfdi", .linkage = common.linkage }); + } +} + +fn __fixsfdi(a: f32) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __aeabi_f2lz(a: f32) callconv(.AAPCS) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixsfsi.zig b/lib/compiler_rt/fixsfsi.zig new file mode 100644 index 0000000000..d48162928b --- /dev/null +++ b/lib/compiler_rt/fixsfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2iz, .{ .name = "__aeabi_f2iz", .linkage = common.linkage }); + } else { + @export(__fixsfsi, .{ .name = "__fixsfsi", .linkage = common.linkage }); + } +} + +fn __fixsfsi(a: f32) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __aeabi_f2iz(a: f32) callconv(.AAPCS) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixsfti.zig b/lib/compiler_rt/fixsfti.zig new file mode 100644 index 0000000000..aefde49768 --- /dev/null +++ b/lib/compiler_rt/fixsfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixsfti, .{ .name = "__fixsfti", .linkage = common.linkage }); +} + +fn __fixsfti(a: f32) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixtfdi.zig b/lib/compiler_rt/fixtfdi.zig new file mode 100644 index 0000000000..8f8d473b1f --- /dev/null +++ b/lib/compiler_rt/fixtfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = common.linkage }); + } else { + @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = common.linkage }); + } +} + +fn __fixtfdi(a: f128) callconv(.C) i64 { + return floatToInt(i64, a); +} + +fn __fixkfdi(a: f128) callconv(.C) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixtfsi.zig b/lib/compiler_rt/fixtfsi.zig new file mode 100644 index 0000000000..507581d0cf --- /dev/null +++ b/lib/compiler_rt/fixtfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = common.linkage }); + } else { + @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = common.linkage }); + } +} + +fn __fixtfsi(a: f128) callconv(.C) i32 { + return floatToInt(i32, a); +} + +fn __fixkfsi(a: f128) callconv(.C) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixtfti.zig b/lib/compiler_rt/fixtfti.zig new file mode 100644 index 0000000000..a50ee5aa7c --- /dev/null +++ b/lib/compiler_rt/fixtfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixtfti, .{ .name = "__fixtfti", .linkage = common.linkage }); +} + +fn __fixtfti(a: f128) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/fixunsdfdi.zig b/lib/compiler_rt/fixunsdfdi.zig new file mode 100644 index 0000000000..afcb969ac6 --- /dev/null +++ b/lib/compiler_rt/fixunsdfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = common.linkage }); + } else { + @export(__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = common.linkage }); + } +} + +fn __fixunsdfdi(a: f64) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __aeabi_d2ulz(a: f64) callconv(.AAPCS) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunsdfsi.zig b/lib/compiler_rt/fixunsdfsi.zig new file mode 100644 index 0000000000..3675eb2c6f --- /dev/null +++ b/lib/compiler_rt/fixunsdfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2uiz, .{ .name = "__aeabi_d2uiz", .linkage = common.linkage }); + } else { + @export(__fixunsdfsi, .{ .name = "__fixunsdfsi", .linkage = common.linkage }); + } +} + +fn __fixunsdfsi(a: f64) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __aeabi_d2uiz(a: f64) callconv(.AAPCS) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunsdfti.zig b/lib/compiler_rt/fixunsdfti.zig new file mode 100644 index 0000000000..96dd242f6d --- /dev/null +++ b/lib/compiler_rt/fixunsdfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsdfti, .{ .name = "__fixunsdfti", .linkage = common.linkage }); +} + +fn __fixunsdfti(a: f64) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunshfdi.zig b/lib/compiler_rt/fixunshfdi.zig new file mode 100644 index 0000000000..5058bc5e68 --- /dev/null +++ b/lib/compiler_rt/fixunshfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfdi, .{ .name = "__fixunshfdi", .linkage = common.linkage }); +} + +fn __fixunshfdi(a: f16) callconv(.C) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunshfsi.zig b/lib/compiler_rt/fixunshfsi.zig new file mode 100644 index 0000000000..5755048814 --- /dev/null +++ b/lib/compiler_rt/fixunshfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfsi, .{ .name = "__fixunshfsi", .linkage = common.linkage }); +} + +fn __fixunshfsi(a: f16) callconv(.C) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunshfti.zig b/lib/compiler_rt/fixunshfti.zig new file mode 100644 index 0000000000..ac013263eb --- /dev/null +++ b/lib/compiler_rt/fixunshfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunshfti, .{ .name = "__fixunshfti", .linkage = common.linkage }); +} + +fn __fixunshfti(a: f16) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunssfdi.zig b/lib/compiler_rt/fixunssfdi.zig new file mode 100644 index 0000000000..223bbcc2b5 --- /dev/null +++ b/lib/compiler_rt/fixunssfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = common.linkage }); + } else { + @export(__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = common.linkage }); + } +} + +fn __fixunssfdi(a: f32) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __aeabi_f2ulz(a: f32) callconv(.AAPCS) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunssfsi.zig b/lib/compiler_rt/fixunssfsi.zig new file mode 100644 index 0000000000..0a113af529 --- /dev/null +++ b/lib/compiler_rt/fixunssfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_f2uiz, .{ .name = "__aeabi_f2uiz", .linkage = common.linkage }); + } else { + @export(__fixunssfsi, .{ .name = "__fixunssfsi", .linkage = common.linkage }); + } +} + +fn __fixunssfsi(a: f32) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __aeabi_f2uiz(a: f32) callconv(.AAPCS) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunssfti.zig b/lib/compiler_rt/fixunssfti.zig new file mode 100644 index 0000000000..6b7690784d --- /dev/null +++ b/lib/compiler_rt/fixunssfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunssfti, .{ .name = "__fixunssfti", .linkage = common.linkage }); +} + +fn __fixunssfti(a: f32) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunstfdi.zig b/lib/compiler_rt/fixunstfdi.zig new file mode 100644 index 0000000000..0130f21139 --- /dev/null +++ b/lib/compiler_rt/fixunstfdi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = common.linkage }); + } else { + @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = common.linkage }); + } +} + +fn __fixunstfdi(a: f128) callconv(.C) u64 { + return floatToInt(u64, a); +} + +fn __fixunskfdi(a: f128) callconv(.C) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunstfsi.zig b/lib/compiler_rt/fixunstfsi.zig new file mode 100644 index 0000000000..78e2cc83d4 --- /dev/null +++ b/lib/compiler_rt/fixunstfsi.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = common.linkage }); + } else { + @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = common.linkage }); + } +} + +fn __fixunstfsi(a: f128) callconv(.C) u32 { + return floatToInt(u32, a); +} + +fn __fixunskfsi(a: f128) callconv(.C) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunstfti.zig b/lib/compiler_rt/fixunstfti.zig new file mode 100644 index 0000000000..ba3a3ed12e --- /dev/null +++ b/lib/compiler_rt/fixunstfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunstfti, .{ .name = "__fixunstfti", .linkage = common.linkage }); +} + +fn __fixunstfti(a: f128) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixunsxfdi.zig b/lib/compiler_rt/fixunsxfdi.zig new file mode 100644 index 0000000000..cb2760af4e --- /dev/null +++ b/lib/compiler_rt/fixunsxfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfdi, .{ .name = "__fixunsxfdi", .linkage = common.linkage }); +} + +fn __fixunsxfdi(a: f80) callconv(.C) u64 { + return floatToInt(u64, a); +} diff --git a/lib/compiler_rt/fixunsxfsi.zig b/lib/compiler_rt/fixunsxfsi.zig new file mode 100644 index 0000000000..bec36abbf4 --- /dev/null +++ b/lib/compiler_rt/fixunsxfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfsi, .{ .name = "__fixunsxfsi", .linkage = common.linkage }); +} + +fn __fixunsxfsi(a: f80) callconv(.C) u32 { + return floatToInt(u32, a); +} diff --git a/lib/compiler_rt/fixunsxfti.zig b/lib/compiler_rt/fixunsxfti.zig new file mode 100644 index 0000000000..f2cd85cf2f --- /dev/null +++ b/lib/compiler_rt/fixunsxfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixunsxfti, .{ .name = "__fixunsxfti", .linkage = common.linkage }); +} + +fn __fixunsxfti(a: f80) callconv(.C) u128 { + return floatToInt(u128, a); +} diff --git a/lib/compiler_rt/fixxfdi.zig b/lib/compiler_rt/fixxfdi.zig new file mode 100644 index 0000000000..0f249e0a92 --- /dev/null +++ b/lib/compiler_rt/fixxfdi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfdi, .{ .name = "__fixxfdi", .linkage = common.linkage }); +} + +fn __fixxfdi(a: f80) callconv(.C) i64 { + return floatToInt(i64, a); +} diff --git a/lib/compiler_rt/fixxfsi.zig b/lib/compiler_rt/fixxfsi.zig new file mode 100644 index 0000000000..ac2158b7b8 --- /dev/null +++ b/lib/compiler_rt/fixxfsi.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfsi, .{ .name = "__fixxfsi", .linkage = common.linkage }); +} + +fn __fixxfsi(a: f80) callconv(.C) i32 { + return floatToInt(i32, a); +} diff --git a/lib/compiler_rt/fixxfti.zig b/lib/compiler_rt/fixxfti.zig new file mode 100644 index 0000000000..fb547f4115 --- /dev/null +++ b/lib/compiler_rt/fixxfti.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const floatToInt = @import("./float_to_int.zig").floatToInt; + +pub const panic = common.panic; + +comptime { + @export(__fixxfti, .{ .name = "__fixxfti", .linkage = common.linkage }); +} + +fn __fixxfti(a: f80) callconv(.C) i128 { + return floatToInt(i128, a); +} diff --git a/lib/compiler_rt/floatXiYf.zig b/lib/compiler_rt/floatXiYf.zig deleted file mode 100644 index 25f5743491..0000000000 --- a/lib/compiler_rt/floatXiYf.zig +++ /dev/null @@ -1,311 +0,0 @@ -const builtin = @import("builtin"); -const std = @import("std"); -const math = std.math; -const expect = std.testing.expect; -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - // Integral -> Float Conversion - - // Conversion to f32 - @export(__floatsisf, .{ .name = "__floatsisf", .linkage = linkage }); - @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = linkage }); - - @export(__floatundisf, .{ .name = "__floatundisf", .linkage = linkage }); - @export(__floatdisf, .{ .name = "__floatdisf", .linkage = linkage }); - - @export(__floattisf, .{ .name = "__floattisf", .linkage = linkage }); - @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = linkage }); - - // Conversion to f64 - @export(__floatsidf, .{ .name = "__floatsidf", .linkage = linkage }); - @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = linkage }); - - @export(__floatdidf, .{ .name = "__floatdidf", .linkage = linkage }); - @export(__floatundidf, .{ .name = "__floatundidf", .linkage = linkage }); - - @export(__floattidf, .{ .name = "__floattidf", .linkage = linkage }); - @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = linkage }); - - // Conversion to f80 - @export(__floatsixf, .{ .name = "__floatsixf", .linkage = linkage }); - @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = linkage }); - - @export(__floatdixf, .{ .name = "__floatdixf", .linkage = linkage }); - @export(__floatundixf, .{ .name = "__floatundixf", .linkage = linkage }); - - @export(__floattixf, .{ .name = "__floattixf", .linkage = linkage }); - @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = linkage }); - - // Conversion to f128 - @export(__floatsitf, .{ .name = "__floatsitf", .linkage = linkage }); - @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = linkage }); - - @export(__floatditf, .{ .name = "__floatditf", .linkage = linkage }); - @export(__floatunditf, .{ .name = "__floatunditf", .linkage = linkage }); - - @export(__floattitf, .{ .name = "__floattitf", .linkage = linkage }); - @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = linkage }); - - if (!is_test) { - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage }); - @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = linkage }); - @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = linkage }); - @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = linkage }); - @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = linkage }); - @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = linkage }); - @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = linkage }); - - @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__floatsikf, .{ .name = "__floatsikf", .linkage = linkage }); - @export(__floatdikf, .{ .name = "__floatdikf", .linkage = linkage }); - @export(__floatundikf, .{ .name = "__floatundikf", .linkage = linkage }); - @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = linkage }); - @export(__floatuntikf, .{ .name = "__floatuntikf", .linkage = linkage }); - } - } -} - -pub fn floatXiYf(comptime T: type, x: anytype) T { - @setRuntimeSafety(is_test); - - if (x == 0) return 0; - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const Z = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(x))); - const uT = std.meta.Int(.unsigned, @bitSizeOf(T)); - const inf = math.inf(T); - const float_bits = @bitSizeOf(T); - const int_bits = @bitSizeOf(@TypeOf(x)); - const exp_bits = math.floatExponentBits(T); - const fractional_bits = math.floatFractionalBits(T); - const exp_bias = math.maxInt(std.meta.Int(.unsigned, exp_bits - 1)); - const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; - const max_exp = exp_bias; - - // Sign - var abs_val = math.absCast(x); - const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; - var result: uT = sign_bit; - - // Compute significand - var exp = int_bits - @clz(Z, abs_val) - 1; - if (int_bits <= fractional_bits or exp <= fractional_bits) { - const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); - - // Shift up result to line up with the significand - no rounding required - result = (@intCast(uT, abs_val) << shift_amt); - result ^= implicit_bit; // Remove implicit integer bit - } else { - var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); - const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; - - // Shift down result and remove implicit integer bit - result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); - - // Round result, including round-to-even for exact ties - result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); - } - - // Compute exponent - if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity - return @bitCast(T, sign_bit | @bitCast(uT, inf)); - - result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); - - // If the result included a carry, we need to restore the explicit integer bit - if (T == f80) result |= 1 << fractional_bits; - - return @bitCast(T, sign_bit | result); -} - -// Conversion to f16 -pub fn __floatsihf(a: i32) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatunsihf(a: u32) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatdihf(a: i64) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatundihf(a: u64) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floattihf(a: i128) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -pub fn __floatuntihf(a: u128) callconv(.C) f16 { - return floatXiYf(f16, a); -} - -// Conversion to f32 -pub fn __floatsisf(a: i32) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatunsisf(a: u32) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatdisf(a: i64) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatundisf(a: u64) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floattisf(a: i128) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -pub fn __floatuntisf(a: u128) callconv(.C) f32 { - return floatXiYf(f32, a); -} - -// Conversion to f64 -pub fn __floatsidf(a: i32) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatunsidf(a: u32) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatdidf(a: i64) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatundidf(a: u64) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floattidf(a: i128) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -pub fn __floatuntidf(a: u128) callconv(.C) f64 { - return floatXiYf(f64, a); -} - -// Conversion to f80 -pub fn __floatsixf(a: i32) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatunsixf(a: u32) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatdixf(a: i64) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatundixf(a: u64) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floattixf(a: i128) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -pub fn __floatuntixf(a: u128) callconv(.C) f80 { - return floatXiYf(f80, a); -} - -// Conversion to f128 -pub fn __floatsitf(a: i32) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatsikf(a: i32) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __floatsitf, .{a}); -} - -pub fn __floatunsitf(a: u32) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatunsikf(a: u32) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __floatunsitf, .{a}); -} - -pub fn __floatditf(a: i64) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatdikf(a: i64) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __floatditf, .{a}); -} - -pub fn __floatunditf(a: u64) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatundikf(a: u64) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __floatunditf, .{a}); -} - -pub fn __floattitf(a: i128) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatuntitf(a: u128) callconv(.C) f128 { - return floatXiYf(f128, a); -} - -pub fn __floatuntikf(a: u128) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __floatuntitf, .{a}); -} - -// Conversion to f32 -pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_i2f(arg: i32) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_ul2f(arg: u64) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -pub fn __aeabi_l2f(arg: i64) callconv(.AAPCS) f32 { - return floatXiYf(f32, arg); -} - -// Conversion to f64 -pub fn __aeabi_ui2d(arg: u32) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_i2d(arg: i32) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_ul2d(arg: u64) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -pub fn __aeabi_l2d(arg: i64) callconv(.AAPCS) f64 { - return floatXiYf(f64, arg); -} - -test { - _ = @import("floatXiYf_test.zig"); -} diff --git a/lib/compiler_rt/float_to_int.zig b/lib/compiler_rt/float_to_int.zig new file mode 100644 index 0000000000..49d41be442 --- /dev/null +++ b/lib/compiler_rt/float_to_int.zig @@ -0,0 +1,55 @@ +const Int = @import("std").meta.Int; +const math = @import("std").math; +const Log2Int = math.Log2Int; + +pub inline fn floatToInt(comptime I: type, a: anytype) I { + const F = @TypeOf(a); + const float_bits = @typeInfo(F).Float.bits; + const int_bits = @typeInfo(I).Int.bits; + const rep_t = Int(.unsigned, float_bits); + const sig_bits = math.floatMantissaBits(F); + const exp_bits = math.floatExponentBits(F); + const fractional_bits = math.floatFractionalBits(F); + + const implicit_bit = if (F != f80) (@as(rep_t, 1) << sig_bits) else 0; + const max_exp = (1 << (exp_bits - 1)); + const exp_bias = max_exp - 1; + const sig_mask = (@as(rep_t, 1) << sig_bits) - 1; + + // Break a into sign, exponent, significand + const a_rep: rep_t = @bitCast(rep_t, a); + const negative = (a_rep >> (float_bits - 1)) != 0; + const exponent = @intCast(i32, (a_rep << 1) >> (sig_bits + 1)) - exp_bias; + const significand: rep_t = (a_rep & sig_mask) | implicit_bit; + + // If the exponent is negative, the result rounds to zero. + if (exponent < 0) return 0; + + // If the value is too large for the integer type, saturate. + switch (@typeInfo(I).Int.signedness) { + .unsigned => { + if (negative) return 0; + if (@intCast(c_uint, exponent) >= @minimum(int_bits, max_exp)) return math.maxInt(I); + }, + .signed => if (@intCast(c_uint, exponent) >= @minimum(int_bits - 1, max_exp)) { + return if (negative) math.minInt(I) else math.maxInt(I); + }, + } + + // If 0 <= exponent < sig_bits, right shift to get the result. + // Otherwise, shift left. + var result: I = undefined; + if (exponent < fractional_bits) { + result = @intCast(I, significand >> @intCast(Log2Int(rep_t), fractional_bits - exponent)); + } else { + result = @intCast(I, significand) << @intCast(Log2Int(I), exponent - fractional_bits); + } + + if ((@typeInfo(I).Int.signedness == .signed) and negative) + return ~result +% 1; + return result; +} + +test { + _ = @import("float_to_int_test.zig"); +} diff --git a/lib/compiler_rt/float_to_int_test.zig b/lib/compiler_rt/float_to_int_test.zig new file mode 100644 index 0000000000..00ed455609 --- /dev/null +++ b/lib/compiler_rt/float_to_int_test.zig @@ -0,0 +1,948 @@ +const std = @import("std"); +const testing = std.testing; +const math = std.math; +const fixXfYi = @import("fixXfYi.zig").fixXfYi; + +// Conversion from f32 +const __fixsfsi = @import("fixXfYi.zig").__fixsfsi; +const __fixunssfsi = @import("fixXfYi.zig").__fixunssfsi; +const __fixsfdi = @import("fixXfYi.zig").__fixsfdi; +const __fixunssfdi = @import("fixXfYi.zig").__fixunssfdi; +const __fixsfti = @import("fixXfYi.zig").__fixsfti; +const __fixunssfti = @import("fixXfYi.zig").__fixunssfti; + +// Conversion from f64 +const __fixdfsi = @import("fixXfYi.zig").__fixdfsi; +const __fixunsdfsi = @import("fixXfYi.zig").__fixunsdfsi; +const __fixdfdi = @import("fixXfYi.zig").__fixdfdi; +const __fixunsdfdi = @import("fixXfYi.zig").__fixunsdfdi; +const __fixdfti = @import("fixXfYi.zig").__fixdfti; +const __fixunsdfti = @import("fixXfYi.zig").__fixunsdfti; + +// Conversion from f128 +const __fixtfsi = @import("fixXfYi.zig").__fixtfsi; +const __fixunstfsi = @import("fixXfYi.zig").__fixunstfsi; +const __fixtfdi = @import("fixXfYi.zig").__fixtfdi; +const __fixunstfdi = @import("fixXfYi.zig").__fixunstfdi; +const __fixtfti = @import("fixXfYi.zig").__fixtfti; +const __fixunstfti = @import("fixXfYi.zig").__fixunstfti; + +fn test__fixsfsi(a: f32, expected: i32) !void { + const x = __fixsfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunssfsi(a: f32, expected: u32) !void { + const x = __fixunssfsi(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); + try testing.expect(x == expected); +} + +fn test__fixunssfdi(a: f32, expected: u64) !void { + const x = __fixunssfdi(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); + try testing.expect(x == expected); +} + +fn test__fixunssfti(a: f32, expected: u128) !void { + const x = __fixunssfti(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__fixdfsi(a: f64, expected: i32) !void { + const x = __fixdfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunsdfsi(a: f64, expected: u32) !void { + const x = __fixunsdfsi(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); + try testing.expect(x == expected); +} + +fn test__fixunsdfdi(a: f64, expected: u64) !void { + const x = __fixunsdfdi(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); + try testing.expect(x == expected); +} + +fn test__fixunsdfti(a: f64, expected: u128) !void { + const x = __fixunsdfti(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__fixtfsi(a: f128, expected: i32) !void { + const x = __fixtfsi(a); + try testing.expect(x == expected); +} + +fn test__fixunstfsi(a: f128, expected: u32) !void { + const x = __fixunstfsi(a); + try testing.expect(x == expected); +} + +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); + try testing.expect(x == expected); +} + +fn test__fixunstfdi(a: f128, expected: u64) !void { + const x = __fixunstfdi(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); +} + +fn test__fixunstfti(a: f128, expected: u128) !void { + const x = __fixunstfti(a); + try testing.expect(x == expected); +} + +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); + + 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); + + try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + 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); + + try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); +} + +test "fixunstfti" { + try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); + + try test__fixunstfti(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__fixunstfti(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); +} + +fn test__fixunshfti(a: f16, expected: u128) !void { + const x = fixXfYi(u128, a); + try testing.expect(x == expected); +} + +test "fixXfYi for f16" { + try test__fixunshfti(math.inf(f16), math.maxInt(u128)); + try test__fixunshfti(math.floatMax(f16), 65504); +} + +fn test__fixunsxfti(a: f80, expected: u128) !void { + const x = fixXfYi(u128, a); + try testing.expect(x == expected); +} + +test "fixXfYi 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)); +} diff --git a/lib/compiler_rt/floatdidf.zig b/lib/compiler_rt/floatdidf.zig new file mode 100644 index 0000000000..9a0ecc6ed4 --- /dev/null +++ b/lib/compiler_rt/floatdidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = common.linkage }); + } else { + @export(__floatdidf, .{ .name = "__floatdidf", .linkage = common.linkage }); + } +} + +fn __floatdidf(a: i64) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_l2d(a: i64) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatdihf.zig b/lib/compiler_rt/floatdihf.zig new file mode 100644 index 0000000000..f2f7236d6f --- /dev/null +++ b/lib/compiler_rt/floatdihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatdihf, .{ .name = "__floatdihf", .linkage = common.linkage }); +} + +fn __floatdihf(a: i64) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatdisf.zig b/lib/compiler_rt/floatdisf.zig new file mode 100644 index 0000000000..d2ad3bb04b --- /dev/null +++ b/lib/compiler_rt/floatdisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = common.linkage }); + } else { + @export(__floatdisf, .{ .name = "__floatdisf", .linkage = common.linkage }); + } +} + +fn __floatdisf(a: i64) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_l2f(a: i64) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatditf.zig b/lib/compiler_rt/floatditf.zig new file mode 100644 index 0000000000..04132b9c24 --- /dev/null +++ b/lib/compiler_rt/floatditf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatdikf, .{ .name = "__floatdikf", .linkage = common.linkage }); + } else { + @export(__floatditf, .{ .name = "__floatditf", .linkage = common.linkage }); + } +} + +fn __floatditf(a: i64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatdikf(a: i64) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatdixf.zig b/lib/compiler_rt/floatdixf.zig new file mode 100644 index 0000000000..7d80fdbeb8 --- /dev/null +++ b/lib/compiler_rt/floatdixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatdixf, .{ .name = "__floatdixf", .linkage = common.linkage }); +} + +fn __floatdixf(a: i64) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatsidf.zig b/lib/compiler_rt/floatsidf.zig new file mode 100644 index 0000000000..1775b08032 --- /dev/null +++ b/lib/compiler_rt/floatsidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = common.linkage }); + } else { + @export(__floatsidf, .{ .name = "__floatsidf", .linkage = common.linkage }); + } +} + +fn __floatsidf(a: i32) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_i2d(a: i32) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatsihf.zig b/lib/compiler_rt/floatsihf.zig new file mode 100644 index 0000000000..84b54298b5 --- /dev/null +++ b/lib/compiler_rt/floatsihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatsihf, .{ .name = "__floatsihf", .linkage = common.linkage }); +} + +fn __floatsihf(a: i32) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatsisf.zig b/lib/compiler_rt/floatsisf.zig new file mode 100644 index 0000000000..45c7f8d6e4 --- /dev/null +++ b/lib/compiler_rt/floatsisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_i2f, .{ .name = "__aeabi_i2f", .linkage = common.linkage }); + } else { + @export(__floatsisf, .{ .name = "__floatsisf", .linkage = common.linkage }); + } +} + +fn __floatsisf(a: i32) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_i2f(a: i32) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatsitf.zig b/lib/compiler_rt/floatsitf.zig new file mode 100644 index 0000000000..24f5e3bf42 --- /dev/null +++ b/lib/compiler_rt/floatsitf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatsikf, .{ .name = "__floatsikf", .linkage = common.linkage }); + } else { + @export(__floatsitf, .{ .name = "__floatsitf", .linkage = common.linkage }); + } +} + +fn __floatsitf(a: i32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatsikf(a: i32) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatsixf.zig b/lib/compiler_rt/floatsixf.zig new file mode 100644 index 0000000000..76d266e17a --- /dev/null +++ b/lib/compiler_rt/floatsixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatsixf, .{ .name = "__floatsixf", .linkage = common.linkage }); +} + +fn __floatsixf(a: i32) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floattidf.zig b/lib/compiler_rt/floattidf.zig new file mode 100644 index 0000000000..54fff192c7 --- /dev/null +++ b/lib/compiler_rt/floattidf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattidf, .{ .name = "__floattidf", .linkage = common.linkage }); +} + +fn __floattidf(a: i128) callconv(.C) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floattihf.zig b/lib/compiler_rt/floattihf.zig new file mode 100644 index 0000000000..c7e45c7d53 --- /dev/null +++ b/lib/compiler_rt/floattihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattihf, .{ .name = "__floattihf", .linkage = common.linkage }); +} + +fn __floattihf(a: i128) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floattisf.zig b/lib/compiler_rt/floattisf.zig new file mode 100644 index 0000000000..bc161d039f --- /dev/null +++ b/lib/compiler_rt/floattisf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattisf, .{ .name = "__floattisf", .linkage = common.linkage }); +} + +fn __floattisf(a: i128) callconv(.C) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floattitf.zig b/lib/compiler_rt/floattitf.zig new file mode 100644 index 0000000000..bcd75d8d83 --- /dev/null +++ b/lib/compiler_rt/floattitf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattitf, .{ .name = "__floattitf", .linkage = common.linkage }); +} + +fn __floattitf(a: i128) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floattixf.zig b/lib/compiler_rt/floattixf.zig new file mode 100644 index 0000000000..def9bef4d5 --- /dev/null +++ b/lib/compiler_rt/floattixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floattixf, .{ .name = "__floattixf", .linkage = common.linkage }); +} + +fn __floattixf(a: i128) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatundidf.zig b/lib/compiler_rt/floatundidf.zig new file mode 100644 index 0000000000..aed9f42139 --- /dev/null +++ b/lib/compiler_rt/floatundidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = common.linkage }); + } else { + @export(__floatundidf, .{ .name = "__floatundidf", .linkage = common.linkage }); + } +} + +fn __floatundidf(a: u64) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_ul2d(a: u64) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatundihf.zig b/lib/compiler_rt/floatundihf.zig new file mode 100644 index 0000000000..6eff8aaec3 --- /dev/null +++ b/lib/compiler_rt/floatundihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatundihf, .{ .name = "__floatundihf", .linkage = common.linkage }); +} + +fn __floatundihf(a: u64) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatundisf.zig b/lib/compiler_rt/floatundisf.zig new file mode 100644 index 0000000000..1e6094cead --- /dev/null +++ b/lib/compiler_rt/floatundisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = common.linkage }); + } else { + @export(__floatundisf, .{ .name = "__floatundisf", .linkage = common.linkage }); + } +} + +fn __floatundisf(a: u64) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_ul2f(a: u64) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatunditf.zig b/lib/compiler_rt/floatunditf.zig new file mode 100644 index 0000000000..40424d1a6c --- /dev/null +++ b/lib/compiler_rt/floatunditf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatundikf, .{ .name = "__floatundikf", .linkage = common.linkage }); + } else { + @export(__floatunditf, .{ .name = "__floatunditf", .linkage = common.linkage }); + } +} + +fn __floatunditf(a: u64) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatundikf(a: u64) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatundixf.zig b/lib/compiler_rt/floatundixf.zig new file mode 100644 index 0000000000..331b74df4f --- /dev/null +++ b/lib/compiler_rt/floatundixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatundixf, .{ .name = "__floatundixf", .linkage = common.linkage }); +} + +fn __floatundixf(a: u64) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatunsidf.zig b/lib/compiler_rt/floatunsidf.zig new file mode 100644 index 0000000000..472167841b --- /dev/null +++ b/lib/compiler_rt/floatunsidf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ui2d, .{ .name = "__aeabi_ui2d", .linkage = common.linkage }); + } else { + @export(__floatunsidf, .{ .name = "__floatunsidf", .linkage = common.linkage }); + } +} + +fn __floatunsidf(a: u32) callconv(.C) f64 { + return intToFloat(f64, a); +} + +fn __aeabi_ui2d(a: u32) callconv(.AAPCS) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatunsihf.zig b/lib/compiler_rt/floatunsihf.zig new file mode 100644 index 0000000000..c95de9c536 --- /dev/null +++ b/lib/compiler_rt/floatunsihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatunsihf, .{ .name = "__floatunsihf", .linkage = common.linkage }); +} + +fn __floatunsihf(a: u32) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatunsisf.zig b/lib/compiler_rt/floatunsisf.zig new file mode 100644 index 0000000000..b2956e9e28 --- /dev/null +++ b/lib/compiler_rt/floatunsisf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_ui2f, .{ .name = "__aeabi_ui2f", .linkage = common.linkage }); + } else { + @export(__floatunsisf, .{ .name = "__floatunsisf", .linkage = common.linkage }); + } +} + +fn __floatunsisf(a: u32) callconv(.C) f32 { + return intToFloat(f32, a); +} + +fn __aeabi_ui2f(a: u32) callconv(.AAPCS) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatunsitf.zig b/lib/compiler_rt/floatunsitf.zig new file mode 100644 index 0000000000..3f626324d2 --- /dev/null +++ b/lib/compiler_rt/floatunsitf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = common.linkage }); + } else { + @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = common.linkage }); + } +} + +fn __floatunsitf(a: u32) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatunsikf(a: u32) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatunsixf.zig b/lib/compiler_rt/floatunsixf.zig new file mode 100644 index 0000000000..40492564fc --- /dev/null +++ b/lib/compiler_rt/floatunsixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatunsixf, .{ .name = "__floatunsixf", .linkage = common.linkage }); +} + +fn __floatunsixf(a: u32) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/floatuntidf.zig b/lib/compiler_rt/floatuntidf.zig new file mode 100644 index 0000000000..5b35379d38 --- /dev/null +++ b/lib/compiler_rt/floatuntidf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntidf, .{ .name = "__floatuntidf", .linkage = common.linkage }); +} + +fn __floatuntidf(a: u128) callconv(.C) f64 { + return intToFloat(f64, a); +} diff --git a/lib/compiler_rt/floatuntihf.zig b/lib/compiler_rt/floatuntihf.zig new file mode 100644 index 0000000000..0263b1da98 --- /dev/null +++ b/lib/compiler_rt/floatuntihf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntihf, .{ .name = "__floatuntihf", .linkage = common.linkage }); +} + +fn __floatuntihf(a: u128) callconv(.C) f16 { + return intToFloat(f16, a); +} diff --git a/lib/compiler_rt/floatuntisf.zig b/lib/compiler_rt/floatuntisf.zig new file mode 100644 index 0000000000..a3799e50b3 --- /dev/null +++ b/lib/compiler_rt/floatuntisf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntisf, .{ .name = "__floatuntisf", .linkage = common.linkage }); +} + +fn __floatuntisf(a: u128) callconv(.C) f32 { + return intToFloat(f32, a); +} diff --git a/lib/compiler_rt/floatuntitf.zig b/lib/compiler_rt/floatuntitf.zig new file mode 100644 index 0000000000..c1b4b21d56 --- /dev/null +++ b/lib/compiler_rt/floatuntitf.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__floatuntikf, .{ .name = "__floatuntikf", .linkage = common.linkage }); + } else { + @export(__floatuntitf, .{ .name = "__floatuntitf", .linkage = common.linkage }); + } +} + +fn __floatuntitf(a: u128) callconv(.C) f128 { + return intToFloat(f128, a); +} + +fn __floatuntikf(a: u128) callconv(.C) f128 { + return intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatuntixf.zig b/lib/compiler_rt/floatuntixf.zig new file mode 100644 index 0000000000..07017d1f57 --- /dev/null +++ b/lib/compiler_rt/floatuntixf.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const intToFloat = @import("./int_to_float.zig").intToFloat; + +pub const panic = common.panic; + +comptime { + @export(__floatuntixf, .{ .name = "__floatuntixf", .linkage = common.linkage }); +} + +pub fn __floatuntixf(a: u128) callconv(.C) f80 { + return intToFloat(f80, a); +} diff --git a/lib/compiler_rt/gedf2.zig b/lib/compiler_rt/gedf2.zig new file mode 100644 index 0000000000..816d690fa0 --- /dev/null +++ b/lib/compiler_rt/gedf2.zig @@ -0,0 +1,36 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = common.linkage }); + @export(__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = common.linkage }); + } else { + @export(__gedf2, .{ .name = "__gedf2", .linkage = common.linkage }); + @export(__gtdf2, .{ .name = "__gtdf2", .linkage = common.linkage }); + } +} + +/// "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 __gedf2(a: f64, b: f64) callconv(.C) i32 { + return @enumToInt(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." +fn __gtdf2(a: f64, b: f64) callconv(.C) i32 { + return __gedf2(a, b); +} + +fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 { + return comparef.cmpf2(f64, comparef.GE, a, b) != .Less; +} + +fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f64, comparef.GE, a, b) == .Greater); +} diff --git a/lib/compiler_rt/gesf2.zig b/lib/compiler_rt/gesf2.zig new file mode 100644 index 0000000000..f29cd173a5 --- /dev/null +++ b/lib/compiler_rt/gesf2.zig @@ -0,0 +1,36 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = common.linkage }); + @export(__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = common.linkage }); + } else { + @export(__gesf2, .{ .name = "__gesf2", .linkage = common.linkage }); + @export(__gtsf2, .{ .name = "__gtsf2", .linkage = common.linkage }); + } +} + +/// "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 __gesf2(a: f32, b: f32) callconv(.C) i32 { + return @enumToInt(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." +fn __gtsf2(a: f32, b: f32) callconv(.C) i32 { + return __gesf2(a, b); +} + +fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 { + return comparef.cmpf2(f32, comparef.GE, a, b) != .Less; +} + +fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 { + return @boolToInt(comparef.cmpf2(f32, comparef.LE, a, b) == .Greater); +} diff --git a/lib/compiler_rt/getf2.zig b/lib/compiler_rt/getf2.zig new file mode 100644 index 0000000000..402d9ad391 --- /dev/null +++ b/lib/compiler_rt/getf2.zig @@ -0,0 +1,36 @@ +///! 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 common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__gekf2, .{ .name = "__gekf2", .linkage = common.linkage }); + @export(__gtkf2, .{ .name = "__gtkf2", .linkage = common.linkage }); + } else { + @export(__getf2, .{ .name = "__getf2", .linkage = common.linkage }); + @export(__gttf2, .{ .name = "__gttf2", .linkage = common.linkage }); + } +} + +/// "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 @enumToInt(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); +} + +fn __gekf2(a: f128, b: f128) callconv(.C) i32 { + return __getf2(a, b); +} + +fn __gtkf2(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 new file mode 100644 index 0000000000..6bb88fbb8f --- /dev/null +++ b/lib/compiler_rt/gexf2.zig @@ -0,0 +1,17 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + @export(__gexf2, .{ .name = "__gexf2", .linkage = common.linkage }); + @export(__gtxf2, .{ .name = "__gtxf2", .linkage = common.linkage }); +} + +fn __gexf2(a: f80, b: f80) callconv(.C) i32 { + return @enumToInt(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_to_float.zig b/lib/compiler_rt/int_to_float.zig new file mode 100644 index 0000000000..135f9e1dbb --- /dev/null +++ b/lib/compiler_rt/int_to_float.zig @@ -0,0 +1,58 @@ +const Int = @import("std").meta.Int; +const math = @import("std").math; + +pub fn intToFloat(comptime T: type, x: anytype) T { + if (x == 0) return 0; + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const Z = Int(.unsigned, @bitSizeOf(@TypeOf(x))); + const uT = Int(.unsigned, @bitSizeOf(T)); + const inf = math.inf(T); + const float_bits = @bitSizeOf(T); + const int_bits = @bitSizeOf(@TypeOf(x)); + const exp_bits = math.floatExponentBits(T); + const fractional_bits = math.floatFractionalBits(T); + const exp_bias = math.maxInt(Int(.unsigned, exp_bits - 1)); + const implicit_bit = if (T != f80) @as(uT, 1) << fractional_bits else 0; + const max_exp = exp_bias; + + // Sign + var abs_val = math.absCast(x); + const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; + var result: uT = sign_bit; + + // Compute significand + var exp = int_bits - @clz(Z, abs_val) - 1; + if (int_bits <= fractional_bits or exp <= fractional_bits) { + const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); + + // Shift up result to line up with the significand - no rounding required + result = (@intCast(uT, abs_val) << shift_amt); + result ^= implicit_bit; // Remove implicit integer bit + } else { + var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); + const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; + + // Shift down result and remove implicit integer bit + result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); + + // Round result, including round-to-even for exact ties + result = ((result + 1) >> 1) & ~@as(uT, @boolToInt(exact_tie)); + } + + // Compute exponent + if ((int_bits > max_exp) and (exp > max_exp)) // If exponent too large, overflow to infinity + return @bitCast(T, sign_bit | @bitCast(uT, inf)); + + result += (@as(uT, exp) + exp_bias) << math.floatMantissaBits(T); + + // If the result included a carry, we need to restore the explicit integer bit + if (T == f80) result |= 1 << fractional_bits; + + return @bitCast(T, sign_bit | result); +} + +test { + _ = @import("floatXiYf_test.zig"); +} diff --git a/lib/compiler_rt/mulXf3.zig b/lib/compiler_rt/mulXf3.zig deleted file mode 100644 index dc6ac98407..0000000000 --- a/lib/compiler_rt/mulXf3.zig +++ /dev/null @@ -1,368 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc - -const std = @import("std"); -const math = std.math; -const builtin = @import("builtin"); -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__mulsf3, .{ .name = "__mulsf3", .linkage = linkage }); - @export(__muldf3, .{ .name = "__muldf3", .linkage = linkage }); - @export(__mulxf3, .{ .name = "__mulxf3", .linkage = linkage }); - @export(__multf3, .{ .name = "__multf3", .linkage = linkage }); - - if (!is_test) { - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = linkage }); - @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__mulkf3, .{ .name = "__mulkf3", .linkage = linkage }); - } - } -} - -pub fn __mulkf3(a: f128, b: f128) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __multf3, .{ a, b }); -} -pub fn __multf3(a: f128, b: f128) callconv(.C) f128 { - return mulXf3(f128, a, b); -} -pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { - return mulXf3(f80, a, b); -} -pub fn __muldf3(a: f64, b: f64) callconv(.C) f64 { - return mulXf3(f64, a, b); -} -pub fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { - return mulXf3(f32, a, b); -} - -pub fn __aeabi_fmul(a: f32, b: f32) callconv(.C) f32 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __mulsf3, .{ a, b }); -} - -pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { - @setRuntimeSafety(false); - return @call(.{ .modifier = .always_inline }, __muldf3, .{ a, b }); -} - -pub fn mulXf3(comptime T: type, a: T, b: T) T { - @setRuntimeSafety(builtin.is_test); - const typeWidth = @typeInfo(T).Float.bits; - const significandBits = math.floatMantissaBits(T); - const fractionalBits = math.floatFractionalBits(T); - const exponentBits = math.floatExponentBits(T); - - const Z = std.meta.Int(.unsigned, typeWidth); - - // ZSignificand is large enough to contain the significand, including an explicit integer bit - const ZSignificand = PowerOfTwoSignificandZ(T); - const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; - - const roundBit = (1 << (ZSignificandBits - 1)); - const signBit = (@as(Z, 1) << (significandBits + exponentBits)); - const maxExponent = ((1 << exponentBits) - 1); - const exponentBias = (maxExponent >> 1); - - const integerBit = (@as(ZSignificand, 1) << fractionalBits); - const quietBit = integerBit >> 1; - const significandMask = (@as(Z, 1) << significandBits) - 1; - - const absMask = signBit - 1; - const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; - const infRep = @bitCast(Z, math.inf(T)); - const minNormalRep = @bitCast(Z, math.floatMin(T)); - - const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); - const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); - const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; - - var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); - var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); - var scale: i32 = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { - const aAbs: Z = @bitCast(Z, a) & absMask; - const bAbs: Z = @bitCast(Z, b) & absMask; - - // NaN * anything = qNaN - if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); - // anything * NaN = qNaN - if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); - - if (aAbs == infRep) { - // infinity * non-zero = +/- infinity - if (bAbs != 0) { - return @bitCast(T, aAbs | productSign); - } else { - // infinity * zero = NaN - return @bitCast(T, qnanRep); - } - } - - if (bAbs == infRep) { - //? non-zero * infinity = +/- infinity - if (aAbs != 0) { - return @bitCast(T, bAbs | productSign); - } else { - // zero * infinity = NaN - return @bitCast(T, qnanRep); - } - } - - // zero * anything = +/- zero - if (aAbs == 0) return @bitCast(T, productSign); - // anything * zero = +/- zero - if (bAbs == 0) return @bitCast(T, productSign); - - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); - if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); - } - - // Or in the implicit significand bit. (If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) - aSignificand |= integerBit; - bSignificand |= integerBit; - - // Get the significand of a*b. Before multiplying the significands, shift - // one of them left to left-align it in the field. Thus, the product will - // have (exponentBits + 2) integral digits, all but two of which must be - // zero. Normalizing this result is just a conditional left-shift by one - // and bumping the exponent accordingly. - var productHi: ZSignificand = undefined; - var productLo: ZSignificand = undefined; - const left_align_shift = ZSignificandBits - fractionalBits - 1; - wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); - - var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; - - // Normalize the significand, adjust exponent if needed. - if ((productHi & integerBit) != 0) { - productExponent +%= 1; - } else { - productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); - productLo = productLo << 1; - } - - // If we have overflowed the type, return +/- infinity. - if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); - - var result: Z = undefined; - if (productExponent <= 0) { - // Result is denormal before rounding - // - // If the result is so small that it just underflows to zero, return - // a zero of the appropriate sign. Mathematically there is no need to - // handle this case separately, but we make it a special case to - // simplify the shift logic. - const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); - if (shift >= ZSignificandBits) return @bitCast(T, productSign); - - // Otherwise, shift the significand of the result so that the round - // bit is the high bit of productLo. - const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); - productLo |= @boolToInt(sticky); - result = productHi; - - // We include the integer bit so that rounding will carry to the exponent, - // but it will be removed later if the result is still denormal - if (significandBits != fractionalBits) result |= integerBit; - } else { - // Result is normal before rounding; insert the exponent. - result = productHi & significandMask; - result |= @intCast(Z, productExponent) << significandBits; - } - - // Final rounding. The final result may overflow to infinity, or underflow - // to zero, but those are the correct results in those cases. We use the - // default IEEE-754 round-to-nearest, ties-to-even rounding mode. - if (productLo > roundBit) result +%= 1; - if (productLo == roundBit) result +%= result & 1; - - // Restore any explicit integer bit, if it was rounded off - if (significandBits != fractionalBits) { - if ((result >> significandBits) != 0) { - result |= integerBit; - } else { - result &= ~integerBit; - } - } - - // Insert the sign of the result: - result |= productSign; - - return @bitCast(T, result); -} - -fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { - @setRuntimeSafety(builtin.is_test); - switch (Z) { - u16 => { - // 16x16 --> 32 bit multiply - const product = @as(u32, a) * @as(u32, b); - hi.* = @intCast(u16, product >> 16); - lo.* = @truncate(u16, product); - }, - u32 => { - // 32x32 --> 64 bit multiply - const product = @as(u64, a) * @as(u64, b); - hi.* = @intCast(u32, product >> 32); - lo.* = @truncate(u32, product); - }, - u64 => { - const S = struct { - fn loWord(x: u64) u64 { - return @truncate(u32, x); - } - fn hiWord(x: u64) u64 { - return @intCast(u32, x >> 32); - } - }; - // 64x64 -> 128 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - // Each of the component 32x32 -> 64 products - const plolo: u64 = S.loWord(a) * S.loWord(b); - const plohi: u64 = S.loWord(a) * S.hiWord(b); - const philo: u64 = S.hiWord(a) * S.loWord(b); - const phihi: u64 = S.hiWord(a) * S.hiWord(b); - // Sum terms that contribute to lo in a way that allows us to get the carry - const r0: u64 = S.loWord(plolo); - const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); - lo.* = r0 +% (r1 << 32); - // Sum terms contributing to hi with the carry from lo - hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; - }, - u128 => { - const Word_LoMask = @as(u64, 0x00000000ffffffff); - const Word_HiMask = @as(u64, 0xffffffff00000000); - const Word_FullMask = @as(u64, 0xffffffffffffffff); - const S = struct { - fn Word_1(x: u128) u64 { - return @truncate(u32, x >> 96); - } - fn Word_2(x: u128) u64 { - return @truncate(u32, x >> 64); - } - fn Word_3(x: u128) u64 { - return @truncate(u32, x >> 32); - } - fn Word_4(x: u128) u64 { - return @truncate(u32, x); - } - }; - // 128x128 -> 256 wide multiply for platforms that don't have such an operation; - // many 64-bit platforms have this operation, but they tend to have hardware - // floating-point, so we don't bother with a special case for them here. - - const product11: u64 = S.Word_1(a) * S.Word_1(b); - const product12: u64 = S.Word_1(a) * S.Word_2(b); - const product13: u64 = S.Word_1(a) * S.Word_3(b); - const product14: u64 = S.Word_1(a) * S.Word_4(b); - const product21: u64 = S.Word_2(a) * S.Word_1(b); - const product22: u64 = S.Word_2(a) * S.Word_2(b); - const product23: u64 = S.Word_2(a) * S.Word_3(b); - const product24: u64 = S.Word_2(a) * S.Word_4(b); - const product31: u64 = S.Word_3(a) * S.Word_1(b); - const product32: u64 = S.Word_3(a) * S.Word_2(b); - const product33: u64 = S.Word_3(a) * S.Word_3(b); - const product34: u64 = S.Word_3(a) * S.Word_4(b); - const product41: u64 = S.Word_4(a) * S.Word_1(b); - const product42: u64 = S.Word_4(a) * S.Word_2(b); - const product43: u64 = S.Word_4(a) * S.Word_3(b); - const product44: u64 = S.Word_4(a) * S.Word_4(b); - - const sum0: u128 = @as(u128, product44); - const sum1: u128 = @as(u128, product34) +% - @as(u128, product43); - const sum2: u128 = @as(u128, product24) +% - @as(u128, product33) +% - @as(u128, product42); - const sum3: u128 = @as(u128, product14) +% - @as(u128, product23) +% - @as(u128, product32) +% - @as(u128, product41); - const sum4: u128 = @as(u128, product13) +% - @as(u128, product22) +% - @as(u128, product31); - const sum5: u128 = @as(u128, product12) +% - @as(u128, product21); - const sum6: u128 = @as(u128, product11); - - const r0: u128 = (sum0 & Word_FullMask) +% - ((sum1 & Word_LoMask) << 32); - const r1: u128 = (sum0 >> 64) +% - ((sum1 >> 32) & Word_FullMask) +% - (sum2 & Word_FullMask) +% - ((sum3 << 32) & Word_HiMask); - - lo.* = r0 +% (r1 << 64); - hi.* = (r1 >> 64) +% - (sum1 >> 96) +% - (sum2 >> 64) +% - (sum3 >> 32) +% - sum4 +% - (sum5 << 32) +% - (sum6 << 64); - }, - else => @compileError("unsupported"), - } -} - -/// Returns a power-of-two integer type that is large enough to contain -/// the significand of T, including an explicit integer bit -fn PowerOfTwoSignificandZ(comptime T: type) type { - const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); - return std.meta.Int(.unsigned, bits); -} - -fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { - @setRuntimeSafety(builtin.is_test); - const Z = PowerOfTwoSignificandZ(T); - const integerBit = @as(Z, 1) << math.floatFractionalBits(T); - - const shift = @clz(Z, significand.*) - @clz(Z, integerBit); - significand.* <<= @intCast(math.Log2Int(Z), shift); - return @as(i32, 1) - shift; -} - -// Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) -// -// This is analogous to an shr version of `@shlWithOverflow` -fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { - @setRuntimeSafety(builtin.is_test); - const typeWidth = @typeInfo(Z).Int.bits; - const S = math.Log2Int(Z); - var inexact = false; - if (count < typeWidth) { - inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; - lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); - hi.* = hi.* >> @intCast(S, count); - } else if (count < 2 * typeWidth) { - inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; - lo.* = hi.* >> @intCast(S, count -% typeWidth); - hi.* = 0; - } else { - inexact = (hi.* | lo.*) != 0; - lo.* = 0; - hi.* = 0; - } - return inexact; -} - -test { - _ = @import("mulXf3_test.zig"); -} diff --git a/lib/compiler_rt/mulXf3_test.zig b/lib/compiler_rt/mulXf3_test.zig deleted file mode 100644 index 6b4f8ca953..0000000000 --- a/lib/compiler_rt/mulXf3_test.zig +++ /dev/null @@ -1,171 +0,0 @@ -// Ported from: -// -// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c - -const std = @import("std"); -const math = std.math; -const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); -const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); - -const __multf3 = @import("mulXf3.zig").__multf3; -const __mulxf3 = @import("mulXf3.zig").__mulxf3; -const __muldf3 = @import("mulXf3.zig").__muldf3; -const __mulsf3 = @import("mulXf3.zig").__mulsf3; - -// return true if equal -// use two 64-bit integers intead of one 128-bit integer -// because 128-bit integer constant can't be assigned directly -fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { - const rep = @bitCast(u128, result); - const hi = @intCast(u64, rep >> 64); - const lo = @truncate(u64, rep); - - if (hi == expectedHi and lo == expectedLo) { - return true; - } - // test other possible NaN representation(signal NaN) - if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { - if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and - ((hi & 0xffffffffffff) > 0 or lo > 0)) - { - return true; - } - } - return false; -} - -fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __multf3(a, b); - - if (compareResultLD(x, expected_hi, expected_lo)) - return; - - @panic("__multf3 test failure"); -} - -fn makeNaN128(rand: u64) f128 { - const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; - const float_result = @bitCast(f128, int_result); - return float_result; -} -test "multf3" { - // qNaN * any = qNaN - try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - - // NaN * any = NaN - const a = makeNaN128(0x800030000000); - try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); - // inf * any = inf - try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); - - // any * any - try test__multf3( - @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), - @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), - 0x400423e7f9e3c9fc, - 0xd906c2c2a85777c4, - ); - - try test__multf3( - @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), - @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), - 0x3fc52a163c6223fc, - 0xc94c4bf0430768b4, - ); - - try test__multf3( - 0x1.234425696abcad34a35eeffefdcbap+456, - 0x451.ed98d76e5d46e5f24323dff21ffp+600, - 0x44293a91de5e0e94, - 0xe8ed17cc2cdf64ac, - ); - - try test__multf3( - @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), - @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), - 0x3d4f37c1a3137cae, - 0xfc6807048bc2836a, - ); - - try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); - - // Denormal operands. - try test__multf3( - 0x0.0000000000000000000000000001p-16382, - 0x1p16383, - 0x3f90000000000000, - 0x0, - ); - try test__multf3( - 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); -} - -const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); - -fn test__mulxf3(a: f80, b: f80, expected: u80) !void { - const x = __mulxf3(a, b); - const rep = @bitCast(u80, x); - - if (rep == expected) - return; - - if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) - return; // We don't currently test NaN payload propagation - - return error.TestFailed; -} - -test "mulxf3" { - // NaN * any = NaN - try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); - - // any * NaN = NaN - try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); - try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); - - // NaN * inf = NaN - try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); - - // inf * NaN = NaN - try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); - - // inf * inf = inf - try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); - - // inf * -inf = -inf - try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); - - // -inf + inf = -inf - try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); - - // inf * any = inf - try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); - - // any * inf = inf - try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, 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__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__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 -} diff --git a/lib/compiler_rt/muldf3.zig b/lib/compiler_rt/muldf3.zig new file mode 100644 index 0000000000..c9142a9ed3 --- /dev/null +++ b/lib/compiler_rt/muldf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dmul, .{ .name = "__aeabi_dmul", .linkage = common.linkage }); + } else { + @export(__muldf3, .{ .name = "__muldf3", .linkage = common.linkage }); + } +} + +fn __muldf3(a: f64, b: f64) callconv(.C) f64 { + return mulf3(f64, a, b); +} + +fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { + return mulf3(f64, a, b); +} diff --git a/lib/compiler_rt/mulf3.zig b/lib/compiler_rt/mulf3.zig new file mode 100644 index 0000000000..f6949ee3ce --- /dev/null +++ b/lib/compiler_rt/mulf3.zig @@ -0,0 +1,203 @@ +const std = @import("std"); +const math = std.math; +const builtin = @import("builtin"); +const common = @import("./common.zig"); + +/// 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 { + @setRuntimeSafety(builtin.is_test); + const typeWidth = @typeInfo(T).Float.bits; + const significandBits = math.floatMantissaBits(T); + const fractionalBits = math.floatFractionalBits(T); + const exponentBits = math.floatExponentBits(T); + + const Z = std.meta.Int(.unsigned, typeWidth); + + // ZSignificand is large enough to contain the significand, including an explicit integer bit + const ZSignificand = PowerOfTwoSignificandZ(T); + const ZSignificandBits = @typeInfo(ZSignificand).Int.bits; + + const roundBit = (1 << (ZSignificandBits - 1)); + const signBit = (@as(Z, 1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const integerBit = (@as(ZSignificand, 1) << fractionalBits); + const quietBit = integerBit >> 1; + const significandMask = (@as(Z, 1) << significandBits) - 1; + + const absMask = signBit - 1; + const qnanRep = @bitCast(Z, math.nan(T)) | quietBit; + const infRep = @bitCast(Z, math.inf(T)); + const minNormalRep = @bitCast(Z, math.floatMin(T)); + + const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); + const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); + const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; + + var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask); + var bSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, b) & significandMask); + var scale: i32 = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent -% 1 >= maxExponent - 1 or bExponent -% 1 >= maxExponent - 1) { + const aAbs: Z = @bitCast(Z, a) & absMask; + const bAbs: Z = @bitCast(Z, b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs != 0) { + return @bitCast(T, aAbs | productSign); + } else { + // infinity * zero = NaN + return @bitCast(T, qnanRep); + } + } + + if (bAbs == infRep) { + //? non-zero * infinity = +/- infinity + if (aAbs != 0) { + return @bitCast(T, bAbs | productSign); + } else { + // zero * infinity = NaN + return @bitCast(T, qnanRep); + } + } + + // zero * anything = +/- zero + if (aAbs == 0) return @bitCast(T, productSign); + // anything * zero = +/- zero + if (bAbs == 0) return @bitCast(T, productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < minNormalRep) scale += normalize(T, &aSignificand); + if (bAbs < minNormalRep) scale += normalize(T, &bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= integerBit; + bSignificand |= integerBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + var productHi: ZSignificand = undefined; + var productLo: ZSignificand = undefined; + const left_align_shift = ZSignificandBits - fractionalBits - 1; + common.wideMultiply(ZSignificand, aSignificand, bSignificand << left_align_shift, &productHi, &productLo); + + var productExponent: i32 = @intCast(i32, aExponent + bExponent) - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if ((productHi & integerBit) != 0) { + productExponent +%= 1; + } else { + productHi = (productHi << 1) | (productLo >> (ZSignificandBits - 1)); + productLo = productLo << 1; + } + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return @bitCast(T, infRep | productSign); + + var result: Z = undefined; + if (productExponent <= 0) { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + const shift: u32 = @truncate(u32, @as(Z, 1) -% @bitCast(u32, productExponent)); + if (shift >= ZSignificandBits) return @bitCast(T, productSign); + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + const sticky = wideShrWithTruncation(ZSignificand, &productHi, &productLo, shift); + productLo |= @boolToInt(sticky); + result = productHi; + + // We include the integer bit so that rounding will carry to the exponent, + // but it will be removed later if the result is still denormal + if (significandBits != fractionalBits) result |= integerBit; + } else { + // Result is normal before rounding; insert the exponent. + result = productHi & significandMask; + result |= @intCast(Z, productExponent) << significandBits; + } + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if (productLo > roundBit) result +%= 1; + if (productLo == roundBit) result +%= result & 1; + + // Restore any explicit integer bit, if it was rounded off + if (significandBits != fractionalBits) { + if ((result >> significandBits) != 0) { + result |= integerBit; + } else { + result &= ~integerBit; + } + } + + // Insert the sign of the result: + result |= productSign; + + return @bitCast(T, result); +} + +/// Returns `true` if the right shift is inexact (i.e. any bit shifted out is non-zero) +/// +/// This is analogous to an shr version of `@shlWithOverflow` +fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { + @setRuntimeSafety(builtin.is_test); + const typeWidth = @typeInfo(Z).Int.bits; + const S = math.Log2Int(Z); + var inexact = false; + if (count < typeWidth) { + inexact = (lo.* << @intCast(S, typeWidth -% count)) != 0; + lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)); + hi.* = hi.* >> @intCast(S, count); + } else if (count < 2 * typeWidth) { + inexact = (hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0; + lo.* = hi.* >> @intCast(S, count -% typeWidth); + hi.* = 0; + } else { + inexact = (hi.* | lo.*) != 0; + lo.* = 0; + hi.* = 0; + } + return inexact; +} + +fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 { + const Z = PowerOfTwoSignificandZ(T); + const integerBit = @as(Z, 1) << math.floatFractionalBits(T); + + const shift = @clz(Z, significand.*) - @clz(Z, integerBit); + significand.* <<= @intCast(math.Log2Int(Z), shift); + return @as(i32, 1) - shift; +} + +/// Returns a power-of-two integer type that is large enough to contain +/// the significand of T, including an explicit integer bit +fn PowerOfTwoSignificandZ(comptime T: type) type { + const bits = math.ceilPowerOfTwoAssert(u16, math.floatFractionalBits(T) + 1); + return std.meta.Int(.unsigned, bits); +} + +test { + _ = @import("mulf3_test.zig"); +} diff --git a/lib/compiler_rt/mulf3_test.zig b/lib/compiler_rt/mulf3_test.zig new file mode 100644 index 0000000000..0c7d84c5e0 --- /dev/null +++ b/lib/compiler_rt/mulf3_test.zig @@ -0,0 +1,171 @@ +// Ported from: +// +// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/test/builtins/Unit/multf3_test.c + +const std = @import("std"); +const math = std.math; +const qnan128 = @bitCast(f128, @as(u128, 0x7fff800000000000) << 64); +const inf128 = @bitCast(f128, @as(u128, 0x7fff000000000000) << 64); + +const __multf3 = @import("mulf3.zig").__multf3; +const __mulxf3 = @import("mulf3.zig").__mulxf3; +const __muldf3 = @import("mulf3.zig").__muldf3; +const __mulsf3 = @import("mulf3.zig").__mulsf3; + +// return true if equal +// use two 64-bit integers intead of one 128-bit integer +// because 128-bit integer constant can't be assigned directly +fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { + const rep = @bitCast(u128, result); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expectedHi and lo == expectedLo) { + return true; + } + // test other possible NaN representation(signal NaN) + if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return true; + } + } + return false; +} + +fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = __multf3(a, b); + + if (compareResultLD(x, expected_hi, expected_lo)) + return; + + @panic("__multf3 test failure"); +} + +fn makeNaN128(rand: u64) f128 { + const int_result = @as(u128, 0x7fff000000000000 | (rand & 0xffffffffffff)) << 64; + const float_result = @bitCast(f128, int_result); + return float_result; +} +test "multf3" { + // qNaN * any = qNaN + try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN * any = NaN + const a = makeNaN128(0x800030000000); + try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + // inf * any = inf + try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + + // any * any + try test__multf3( + @bitCast(f128, @as(u128, 0x40042eab345678439abcdefea5678234)), + @bitCast(f128, @as(u128, 0x3ffeedcb34a235253948765432134675)), + 0x400423e7f9e3c9fc, + 0xd906c2c2a85777c4, + ); + + try test__multf3( + @bitCast(f128, @as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50)), + @bitCast(f128, @as(u128, 0x3ff6ed8764648369535adf4be3214568)), + 0x3fc52a163c6223fc, + 0xc94c4bf0430768b4, + ); + + try test__multf3( + 0x1.234425696abcad34a35eeffefdcbap+456, + 0x451.ed98d76e5d46e5f24323dff21ffp+600, + 0x44293a91de5e0e94, + 0xe8ed17cc2cdf64ac, + ); + + try test__multf3( + @bitCast(f128, @as(u128, 0x3f154356473c82a9fabf2d22ace345df)), + @bitCast(f128, @as(u128, 0x3e38eda98765476743ab21da23d45679)), + 0x3d4f37c1a3137cae, + 0xfc6807048bc2836a, + ); + + try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); + + // Denormal operands. + try test__multf3( + 0x0.0000000000000000000000000001p-16382, + 0x1p16383, + 0x3f90000000000000, + 0x0, + ); + try test__multf3( + 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); +} + +const qnan80 = @bitCast(f80, @bitCast(u80, math.nan(f80)) | (1 << (math.floatFractionalBits(f80) - 1))); + +fn test__mulxf3(a: f80, b: f80, expected: u80) !void { + const x = __mulxf3(a, b); + const rep = @bitCast(u80, x); + + if (rep == expected) + return; + + if (math.isNan(@bitCast(f80, expected)) and math.isNan(x)) + return; // We don't currently test NaN payload propagation + + return error.TestFailed; +} + +test "mulxf3" { + // NaN * any = NaN + try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + try test__mulxf3(@bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), 0x1.23456789abcdefp+5, @bitCast(u80, qnan80)); + + // any * NaN = NaN + try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @bitCast(u80, qnan80)); + try test__mulxf3(0x1.23456789abcdefp+5, @bitCast(f80, @as(u80, 0x7fff_8000_8000_3000_0000)), @bitCast(u80, qnan80)); + + // NaN * inf = NaN + try test__mulxf3(qnan80, math.inf(f80), @bitCast(u80, qnan80)); + + // inf * NaN = NaN + try test__mulxf3(math.inf(f80), qnan80, @bitCast(u80, qnan80)); + + // inf * inf = inf + try test__mulxf3(math.inf(f80), math.inf(f80), @bitCast(u80, math.inf(f80))); + + // inf * -inf = -inf + try test__mulxf3(math.inf(f80), -math.inf(f80), @bitCast(u80, -math.inf(f80))); + + // -inf + inf = -inf + try test__mulxf3(-math.inf(f80), math.inf(f80), @bitCast(u80, -math.inf(f80))); + + // inf * any = inf + try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @bitCast(u80, math.inf(f80))); + + // any * inf = inf + try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @bitCast(u80, 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__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__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 +} diff --git a/lib/compiler_rt/mulsf3.zig b/lib/compiler_rt/mulsf3.zig new file mode 100644 index 0000000000..a425f9617e --- /dev/null +++ b/lib/compiler_rt/mulsf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fmul, .{ .name = "__aeabi_fmul", .linkage = common.linkage }); + } else { + @export(__mulsf3, .{ .name = "__mulsf3", .linkage = common.linkage }); + } +} + +fn __mulsf3(a: f32, b: f32) callconv(.C) f32 { + return mulf3(f32, a, b); +} + +fn __aeabi_fmul(a: f32, b: f32) callconv(.C) f32 { + return mulf3(f32, a, b); +} diff --git a/lib/compiler_rt/multf3.zig b/lib/compiler_rt/multf3.zig new file mode 100644 index 0000000000..f71867c9ca --- /dev/null +++ b/lib/compiler_rt/multf3.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__mulkf3, .{ .name = "__mulkf3", .linkage = common.linkage }); + } else { + @export(__multf3, .{ .name = "__multf3", .linkage = common.linkage }); + } +} + +fn __multf3(a: f128, b: f128) callconv(.C) f128 { + return mulf3(f128, a, b); +} + +fn __mulkf3(a: f128, b: f128) callconv(.C) f128 { + return mulf3(f128, a, b); +} diff --git a/lib/compiler_rt/mulxf3.zig b/lib/compiler_rt/mulxf3.zig new file mode 100644 index 0000000000..353d27c290 --- /dev/null +++ b/lib/compiler_rt/mulxf3.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const mulf3 = @import("./mulf3.zig").mulf3; + +pub const panic = common.panic; + +comptime { + @export(__mulxf3, .{ .name = "__mulxf3", .linkage = common.linkage }); +} + +pub fn __mulxf3(a: f80, b: f80) callconv(.C) f80 { + return mulf3(f80, a, b); +} diff --git a/lib/compiler_rt/sparc.zig b/lib/compiler_rt/sparc.zig index f96ba4b41a..a39951a1c8 100644 --- a/lib/compiler_rt/sparc.zig +++ b/lib/compiler_rt/sparc.zig @@ -50,7 +50,7 @@ const FCMP = enum(i32) { // Basic arithmetic pub fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addXf3.zig").__addtf3(a.*, b.*); + c.* = @import("addf3.zig").__addtf3(a.*, b.*); } pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { @@ -58,11 +58,11 @@ pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { } pub fn _Qp_mul(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("mulXf3.zig").__multf3(a.*, b.*); + c.* = @import("mulf3.zig").__multf3(a.*, b.*); } pub fn _Qp_sub(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addXf3.zig").__subtf3(a.*, b.*); + c.* = @import("addf3.zig").__subtf3(a.*, b.*); } // Comparison diff --git a/lib/compiler_rt/subdf3.zig b/lib/compiler_rt/subdf3.zig new file mode 100644 index 0000000000..9d62ffe480 --- /dev/null +++ b/lib/compiler_rt/subdf3.zig @@ -0,0 +1,21 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dsub, .{ .name = "__aeabi_dsub", .linkage = common.linkage }); + } else { + @export(__subdf3, .{ .name = "__subdf3", .linkage = common.linkage }); + } +} + +fn __subdf3(a: f64, b: f64) callconv(.C) f64 { + const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); + return a + neg_b; +} + +fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { + const neg_b = @bitCast(f64, @bitCast(u64, b) ^ (@as(u64, 1) << 63)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subsf3.zig b/lib/compiler_rt/subsf3.zig new file mode 100644 index 0000000000..472bccc899 --- /dev/null +++ b/lib/compiler_rt/subsf3.zig @@ -0,0 +1,21 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fsub, .{ .name = "__aeabi_fsub", .linkage = common.linkage }); + } else { + @export(__subsf3, .{ .name = "__subsf3", .linkage = common.linkage }); + } +} + +fn __subsf3(a: f32, b: f32) callconv(.C) f32 { + const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); + return a + neg_b; +} + +fn __aeabi_fsub(a: f32, b: f32) callconv(.AAPCS) f32 { + const neg_b = @bitCast(f32, @bitCast(u32, b) ^ (@as(u32, 1) << 31)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subtf3.zig b/lib/compiler_rt/subtf3.zig new file mode 100644 index 0000000000..a4e2f4dfae --- /dev/null +++ b/lib/compiler_rt/subtf3.zig @@ -0,0 +1,21 @@ +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__subkf3, .{ .name = "__subkf3", .linkage = common.linkage }); + } else { + @export(__subtf3, .{ .name = "__subtf3", .linkage = common.linkage }); + } +} + +fn __subtf3(a: f128, b: f128) callconv(.C) f128 { + const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); + return a + neg_b; +} + +fn __subkf3(a: f128, b: f128) callconv(.C) f128 { + const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); + return a + neg_b; +} diff --git a/lib/compiler_rt/subxf3.zig b/lib/compiler_rt/subxf3.zig new file mode 100644 index 0000000000..a143f10ffe --- /dev/null +++ b/lib/compiler_rt/subxf3.zig @@ -0,0 +1,15 @@ +const std = @import("std"); +const common = @import("./common.zig"); + +pub const panic = common.panic; + +comptime { + @export(__subxf3, .{ .name = "__subxf3", .linkage = common.linkage }); +} + +fn __subxf3(a: f80, b: f80) callconv(.C) f80 { + var b_rep = std.math.break_f80(b); + b_rep.exp ^= 0x8000; + const neg_b = std.math.make_f80(b_rep); + return a + neg_b; +} diff --git a/lib/compiler_rt/truncXfYf2.zig b/lib/compiler_rt/truncXfYf2.zig deleted file mode 100644 index 77fabcbd75..0000000000 --- a/lib/compiler_rt/truncXfYf2.zig +++ /dev/null @@ -1,192 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage }); - @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage }); - @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage }); - @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage }); - - @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage }); - @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage }); - - if (!is_test) { - @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = linkage }); - - if (arch.isARM() or arch.isThumb()) { - @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = linkage }); - @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = linkage }); - @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = linkage }); - } - - if (arch.isPPC() or arch.isPPC64()) { - @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = linkage }); - @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = linkage }); - } - } -} - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -// TODO remove this; do this type selection in the language rather than -// here in compiler-rt. -const F16T = if (arch.isAARCH64()) f16 else u16; - -pub fn __truncsfhf2(a: f32) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f32, a)); -} - -pub fn __gnu_f2h_ieee(a: f32) callconv(.C) F16T { - return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a}); -} - -pub fn __truncdfhf2(a: f64) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f64, a)); -} - -pub fn __trunctfhf2(a: f128) callconv(.C) F16T { - return @bitCast(F16T, truncXfYf2(f16, f128, a)); -} - -pub fn __trunctfsf2(a: f128) callconv(.C) f32 { - return truncXfYf2(f32, f128, a); -} - -pub fn __trunckfsf2(a: f128) callconv(.C) f32 { - return truncXfYf2(f32, f128, a); -} - -pub fn __trunctfdf2(a: f128) callconv(.C) f64 { - return truncXfYf2(f64, f128, a); -} - -pub fn __trunckfdf2(a: f128) callconv(.C) f64 { - return truncXfYf2(f64, f128, a); -} - -pub fn __truncdfsf2(a: f64) callconv(.C) f32 { - return truncXfYf2(f32, f64, a); -} - -pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { - @setRuntimeSafety(false); - return truncXfYf2(f32, f64, a); -} - -pub fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { - @setRuntimeSafety(false); - return @bitCast(F16T, truncXfYf2(f16, f64, a)); -} - -pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { - @setRuntimeSafety(false); - return @bitCast(F16T, truncXfYf2(f16, f32, a)); -} - -inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { - const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); - const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); - const srcSigBits = std.math.floatMantissaBits(src_t); - const dstSigBits = std.math.floatMantissaBits(dst_t); - const SrcShift = std.math.Log2Int(src_rep_t); - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const srcBits = @typeInfo(src_t).Float.bits; - const srcExpBits = srcBits - srcSigBits - 1; - const srcInfExp = (1 << srcExpBits) - 1; - const srcExpBias = srcInfExp >> 1; - - const srcMinNormal = 1 << srcSigBits; - const srcSignificandMask = srcMinNormal - 1; - const srcInfinity = srcInfExp << srcSigBits; - const srcSignMask = 1 << (srcSigBits + srcExpBits); - const srcAbsMask = srcSignMask - 1; - const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; - const halfway = 1 << (srcSigBits - dstSigBits - 1); - const srcQNaN = 1 << (srcSigBits - 1); - const srcNaNCode = srcQNaN - 1; - - const dstBits = @typeInfo(dst_t).Float.bits; - const dstExpBits = dstBits - dstSigBits - 1; - const dstInfExp = (1 << dstExpBits) - 1; - const dstExpBias = dstInfExp >> 1; - - const underflowExponent = srcExpBias + 1 - dstExpBias; - const overflowExponent = srcExpBias + dstInfExp - dstExpBias; - const underflow = underflowExponent << srcSigBits; - const overflow = overflowExponent << srcSigBits; - - const dstQNaN = 1 << (dstSigBits - 1); - const dstNaNCode = dstQNaN - 1; - - // Break a into a sign and representation of the absolute value - const aRep: src_rep_t = @bitCast(src_rep_t, a); - const aAbs: src_rep_t = aRep & srcAbsMask; - const sign: src_rep_t = aRep & srcSignMask; - var absResult: dst_rep_t = undefined; - - if (aAbs -% underflow < aAbs -% overflow) { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding and adjusting the exponent. - absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); - absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; - - const roundBits: src_rep_t = aAbs & roundMask; - if (roundBits > halfway) { - // Round to nearest - absResult += 1; - } else if (roundBits == halfway) { - // Ties to even - absResult += absResult & 1; - } - } else if (aAbs > srcInfinity) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; - absResult |= dstQNaN; - absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); - } else if (aAbs >= overflow) { - // a overflows to infinity. - absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - const aExp = @intCast(u32, aAbs >> srcSigBits); - const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); - - const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; - - // Right shift by the denormalization amount with sticky. - if (shift > srcSigBits) { - absResult = 0; - } else { - const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); - const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; - absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); - const roundBits: src_rep_t = denormalizedSignificand & roundMask; - if (roundBits > halfway) { - // Round to nearest - absResult += 1; - } else if (roundBits == halfway) { - // Ties to even - absResult += absResult & 1; - } - } - } - - const result: dst_rep_t align(@alignOf(dst_t)) = absResult | - @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); - return @bitCast(dst_t, result); -} - -test { - _ = @import("truncXfYf2_test.zig"); -} diff --git a/lib/compiler_rt/truncXfYf2_test.zig b/lib/compiler_rt/truncXfYf2_test.zig deleted file mode 100644 index 3f11dd0380..0000000000 --- a/lib/compiler_rt/truncXfYf2_test.zig +++ /dev/null @@ -1,296 +0,0 @@ -const std = @import("std"); -const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; - -fn test__truncsfhf2(a: u32, expected: u16) !void { - const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); - - if (actual == expected) { - return; - } - - return error.TestFailure; -} - -test "truncsfhf2" { - try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN - try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN - - try test__truncsfhf2(0, 0); // 0 - try test__truncsfhf2(0x80000000, 0x8000); // -0 - - try test__truncsfhf2(0x7f800000, 0x7c00); // inf - try test__truncsfhf2(0xff800000, 0xfc00); // -inf - - try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf - try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf - - try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf - try test__truncsfhf2(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__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 - try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 - - try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 - try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 - - try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 - try test__truncsfhf2(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__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 - try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 - - try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 - try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 - - try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 - - try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 - try test__truncsfhf2(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__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 - try test__truncsfhf2(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 -} - -const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; - -fn test__truncdfhf2(a: f64, expected: u16) void { - const rep = @bitCast(u16, __truncdfhf2(a)); - - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7e00) { - if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { - return; - } - } - - @panic("__truncdfhf2 test failure"); -} - -fn test__truncdfhf2_raw(a: u64, expected: u16) void { - const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); - - if (actual == expected) { - return; - } - - @panic("__truncdfhf2 test failure"); -} - -test "truncdfhf2" { - test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN - test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN - - test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf - test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf - - test__truncdfhf2(0.0, 0x0); // zero - test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero - - test__truncdfhf2(3.1415926535, 0x4248); - test__truncdfhf2(-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); - - // 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); - - // and back to zero - test__truncdfhf2(0x1.0p-25, 0x0000); - test__truncdfhf2(-0x1.0p-25, 0x8000); - - // max (precise) - test__truncdfhf2(65504.0, 0x7bff); - - // max (rounded) - test__truncdfhf2(65519.0, 0x7bff); - - // max (to +inf) - test__truncdfhf2(65520.0, 0x7c00); - test__truncdfhf2(-65520.0, 0xfc00); - test__truncdfhf2(65536.0, 0x7c00); -} - -const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; - -fn test__trunctfsf2(a: f128, expected: u32) void { - const x = __trunctfsf2(a); - - const rep = @bitCast(u32, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { - if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { - return; - } - } - - @panic("__trunctfsf2 test failure"); -} - -test "trunctfsf2" { - // qnan - test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); - // nan - test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); - // inf - test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); - // zero - test__trunctfsf2(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); -} - -const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2; - -fn test__trunctfdf2(a: f128, expected: u64) void { - const x = __trunctfdf2(a); - - const rep = @bitCast(u64, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7ff8000000000000) { - if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { - return; - } - } - - @panic("__trunctfsf2 test failure"); -} - -test "trunctfdf2" { - // qnan - test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); - // nan - test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); - // inf - test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); - // zero - test__trunctfdf2(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); -} - -const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; - -fn test__truncdfsf2(a: f64, expected: u32) void { - const x = __truncdfsf2(a); - - const rep = @bitCast(u32, x); - if (rep == expected) { - return; - } - // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { - if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { - return; - } - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfsf2 test failure"); -} - -test "truncdfsf2" { - // nan & qnan - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); - // inf - test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); - test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); - - test__truncdfsf2(0.0, 0x0); - test__truncdfsf2(1.0, 0x3f800000); - test__truncdfsf2(-1.0, 0xbf800000); - - // huge number becomes inf - test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); -} - -const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; - -fn test__trunctfhf2(a: f128, expected: u16) void { - const x = __trunctfhf2(a); - - const rep = @bitCast(u16, x); - if (rep == expected) { - return; - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfhf2 test failure"); -} - -test "trunctfhf2" { - // qNaN - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); - // NaN - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); - // inf - test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); - test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); - // zero - test__trunctfhf2(0.0, 0x0); - test__trunctfhf2(-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); - // 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); - // and back to zero - test__trunctfhf2(0x1.0p-25, 0x0000); - test__trunctfhf2(-0x1.0p-25, 0x8000); - // max (precise) - test__trunctfhf2(65504.0, 0x7bff); - // max (rounded) - test__trunctfhf2(65519.0, 0x7bff); - // max (to +inf) - test__trunctfhf2(65520.0, 0x7c00); - test__trunctfhf2(65536.0, 0x7c00); - test__trunctfhf2(-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); -} diff --git a/lib/compiler_rt/trunc_f80.zig b/lib/compiler_rt/trunc_f80.zig deleted file mode 100644 index 43f113ea42..0000000000 --- a/lib/compiler_rt/trunc_f80.zig +++ /dev/null @@ -1,183 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const arch = builtin.cpu.arch; -const testing = std.testing; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = linkage }); - @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = linkage }); - @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = linkage }); - @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = linkage }); -} - -// AArch64 is the only ABI (at the moment) to support f16 arguments without the -// need for extending them to wider fp types. -const F16T = if (arch.isAARCH64()) f16 else u16; - -pub fn __truncxfhf2(a: f80) callconv(.C) F16T { - return @bitCast(F16T, trunc(f16, a)); -} - -pub fn __truncxfsf2(a: f80) callconv(.C) f32 { - return trunc(f32, a); -} - -pub fn __truncxfdf2(a: f80) callconv(.C) f64 { - return trunc(f64, a); -} - -inline fn trunc(comptime dst_t: type, a: f80) dst_t { - @setRuntimeSafety(builtin.is_test); - - const dst_rep_t = std.meta.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); - - const src_exp_bias = 16383; - - const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; - const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); - - const dst_bits = @typeInfo(dst_t).Float.bits; - const dst_exp_bits = dst_bits - dst_sig_bits - 1; - const dst_inf_exp = (1 << dst_exp_bits) - 1; - const dst_exp_bias = dst_inf_exp >> 1; - - const underflow = src_exp_bias + 1 - dst_exp_bias; - const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; - - const dst_qnan = 1 << (dst_sig_bits - 1); - const dst_nan_mask = dst_qnan - 1; - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.break_f80(a); - const sign = a_rep.exp & 0x8000; - a_rep.exp &= 0x7FFF; - a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; - var abs_result: dst_rep_t = undefined; - - if (a_rep.exp -% underflow < a_rep.exp -% overflow) { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding and adjusting the exponent. - abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; - abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); - abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; - - const round_bits = a_rep.fraction & round_mask; - if (round_bits > halfway) { - // Round to nearest - abs_result += 1; - } else if (round_bits == halfway) { - // Ties to even - abs_result += abs_result & 1; - } - } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; - abs_result |= dst_qnan; - abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); - } else if (a_rep.exp >= overflow) { - // a overflows to infinity. - abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - const shift = src_exp_bias - dst_exp_bias - a_rep.exp; - - // Right shift by the denormalization amount with sticky. - if (shift > src_sig_bits) { - abs_result = 0; - } else { - const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); - const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; - abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); - const round_bits = denormalized_significand & round_mask; - if (round_bits > halfway) { - // Round to nearest - abs_result += 1; - } else if (round_bits == halfway) { - // Ties to even - abs_result += abs_result & 1; - } - } - } - - const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; - return @bitCast(dst_t, result); -} - -pub fn __trunctfxf2(a: f128) callconv(.C) 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 = @bitCast(u128, 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 |= @truncate(u64, 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 = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; - res.exp = @truncate(u16, a_abs >> src_sig_bits); - - const round_bits = a_abs & round_mask; - if (round_bits > halfway) { - // Round to nearest - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry - } else if (round_bits == halfway) { - // Ties to even - const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); - res.exp += carry; - res.fraction |= @as(u64, carry) << 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 std.math.make_f80(res); -} - -fn test__trunctfxf2(a: f128, expected: f80) !void { - const x = __trunctfxf2(a); - try testing.expect(x == expected); -} - -test { - 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); -} diff --git a/lib/compiler_rt/truncdfhf2.zig b/lib/compiler_rt/truncdfhf2.zig new file mode 100644 index 0000000000..6d4135d249 --- /dev/null +++ b/lib/compiler_rt/truncdfhf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2h, .{ .name = "__aeabi_d2h", .linkage = common.linkage }); + } else { + @export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = common.linkage }); + } +} + +fn __truncdfhf2(a: f64) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f64, a)); +} + +fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 { + return @bitCast(common.F16T, truncf(f16, f64, a)); +} diff --git a/lib/compiler_rt/truncdfsf2.zig b/lib/compiler_rt/truncdfsf2.zig new file mode 100644 index 0000000000..adf7705821 --- /dev/null +++ b/lib/compiler_rt/truncdfsf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_d2f, .{ .name = "__aeabi_d2f", .linkage = common.linkage }); + } else { + @export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = common.linkage }); + } +} + +fn __truncdfsf2(a: f64) callconv(.C) f32 { + return truncf(f32, f64, a); +} + +fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { + return truncf(f32, f64, a); +} diff --git a/lib/compiler_rt/truncf.zig b/lib/compiler_rt/truncf.zig new file mode 100644 index 0000000000..c012bcee62 --- /dev/null +++ b/lib/compiler_rt/truncf.zig @@ -0,0 +1,187 @@ +const std = @import("std"); + +pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { + const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits); + const srcSigBits = std.math.floatMantissaBits(src_t); + const dstSigBits = std.math.floatMantissaBits(dst_t); + const SrcShift = std.math.Log2Int(src_rep_t); + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const srcBits = @typeInfo(src_t).Float.bits; + const srcExpBits = srcBits - srcSigBits - 1; + const srcInfExp = (1 << srcExpBits) - 1; + const srcExpBias = srcInfExp >> 1; + + const srcMinNormal = 1 << srcSigBits; + const srcSignificandMask = srcMinNormal - 1; + const srcInfinity = srcInfExp << srcSigBits; + const srcSignMask = 1 << (srcSigBits + srcExpBits); + const srcAbsMask = srcSignMask - 1; + const roundMask = (1 << (srcSigBits - dstSigBits)) - 1; + const halfway = 1 << (srcSigBits - dstSigBits - 1); + const srcQNaN = 1 << (srcSigBits - 1); + const srcNaNCode = srcQNaN - 1; + + const dstBits = @typeInfo(dst_t).Float.bits; + const dstExpBits = dstBits - dstSigBits - 1; + const dstInfExp = (1 << dstExpBits) - 1; + const dstExpBias = dstInfExp >> 1; + + const underflowExponent = srcExpBias + 1 - dstExpBias; + const overflowExponent = srcExpBias + dstInfExp - dstExpBias; + const underflow = underflowExponent << srcSigBits; + const overflow = overflowExponent << srcSigBits; + + const dstQNaN = 1 << (dstSigBits - 1); + const dstNaNCode = dstQNaN - 1; + + // Break a into a sign and representation of the absolute value + const aRep: src_rep_t = @bitCast(src_rep_t, a); + const aAbs: src_rep_t = aRep & srcAbsMask; + const sign: src_rep_t = aRep & srcSignMask; + var absResult: dst_rep_t = undefined; + + if (aAbs -% underflow < aAbs -% overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits)); + absResult -%= @as(dst_rep_t, srcExpBias - dstExpBias) << dstSigBits; + + const roundBits: src_rep_t = aAbs & roundMask; + if (roundBits > halfway) { + // Round to nearest + absResult += 1; + } else if (roundBits == halfway) { + // Ties to even + absResult += absResult & 1; + } + } else if (aAbs > srcInfinity) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; + absResult |= dstQNaN; + absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode); + } else if (aAbs >= overflow) { + // a overflows to infinity. + absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits; + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const aExp = @intCast(u32, aAbs >> srcSigBits); + const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1); + + const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal; + + // Right shift by the denormalization amount with sticky. + if (shift > srcSigBits) { + absResult = 0; + } else { + const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0); + const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; + absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); + const roundBits: src_rep_t = denormalizedSignificand & roundMask; + if (roundBits > halfway) { + // Round to nearest + absResult += 1; + } else if (roundBits == halfway) { + // Ties to even + absResult += absResult & 1; + } + } + } + + const result: dst_rep_t align(@alignOf(dst_t)) = absResult | + @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits)); + return @bitCast(dst_t, result); +} + +pub inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { + const dst_rep_t = std.meta.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); + + const src_exp_bias = 16383; + + const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; + const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); + + const dst_bits = @typeInfo(dst_t).Float.bits; + const dst_exp_bits = dst_bits - dst_sig_bits - 1; + const dst_inf_exp = (1 << dst_exp_bits) - 1; + const dst_exp_bias = dst_inf_exp >> 1; + + const underflow = src_exp_bias + 1 - dst_exp_bias; + const overflow = src_exp_bias + dst_inf_exp - dst_exp_bias; + + const dst_qnan = 1 << (dst_sig_bits - 1); + const dst_nan_mask = dst_qnan - 1; + + // Break a into a sign and representation of the absolute value + var a_rep = std.math.break_f80(a); + const sign = a_rep.exp & 0x8000; + a_rep.exp &= 0x7FFF; + a_rep.fraction &= 0x7FFFFFFFFFFFFFFF; + var abs_result: dst_rep_t = undefined; + + if (a_rep.exp -% underflow < a_rep.exp -% overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + abs_result = @as(dst_rep_t, a_rep.exp) << dst_sig_bits; + abs_result |= @truncate(dst_rep_t, a_rep.fraction >> (src_sig_bits - dst_sig_bits)); + abs_result -%= @as(dst_rep_t, src_exp_bias - dst_exp_bias) << dst_sig_bits; + + const round_bits = a_rep.fraction & round_mask; + if (round_bits > halfway) { + // Round to nearest + abs_result += 1; + } else if (round_bits == halfway) { + // Ties to even + abs_result += abs_result & 1; + } + } else if (a_rep.exp == 0x7FFF and a_rep.fraction != 0) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; + abs_result |= dst_qnan; + abs_result |= @intCast(dst_rep_t, (a_rep.fraction >> (src_sig_bits - dst_sig_bits)) & dst_nan_mask); + } else if (a_rep.exp >= overflow) { + // a overflows to infinity. + abs_result = @intCast(dst_rep_t, dst_inf_exp) << dst_sig_bits; + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const shift = src_exp_bias - dst_exp_bias - a_rep.exp; + + // Right shift by the denormalization amount with sticky. + if (shift > src_sig_bits) { + abs_result = 0; + } else { + const sticky = @boolToInt(a_rep.fraction << @intCast(u6, shift) != 0); + const denormalized_significand = a_rep.fraction >> @intCast(u6, shift) | sticky; + abs_result = @intCast(dst_rep_t, denormalized_significand >> (src_sig_bits - dst_sig_bits)); + const round_bits = denormalized_significand & round_mask; + if (round_bits > halfway) { + // Round to nearest + abs_result += 1; + } else if (round_bits == halfway) { + // Ties to even + abs_result += abs_result & 1; + } + } + } + + const result align(@alignOf(dst_t)) = abs_result | @as(dst_rep_t, sign) << dst_bits - 16; + return @bitCast(dst_t, result); +} + +test { + _ = @import("truncf_test.zig"); +} diff --git a/lib/compiler_rt/truncf_test.zig b/lib/compiler_rt/truncf_test.zig new file mode 100644 index 0000000000..58c02a0a21 --- /dev/null +++ b/lib/compiler_rt/truncf_test.zig @@ -0,0 +1,310 @@ +const std = @import("std"); +const testing = std.testing; +const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2; +const __trunctfxf2 = @import("trunctfxf2.zig").__trunctfxf2; + +fn test__truncsfhf2(a: u32, expected: u16) !void { + const actual = @bitCast(u16, __truncsfhf2(@bitCast(f32, a))); + + if (actual == expected) { + return; + } + + return error.TestFailure; +} + +test "truncsfhf2" { + try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN + try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN + + try test__truncsfhf2(0, 0); // 0 + try test__truncsfhf2(0x80000000, 0x8000); // -0 + + try test__truncsfhf2(0x7f800000, 0x7c00); // inf + try test__truncsfhf2(0xff800000, 0xfc00); // -inf + + try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf + try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf + + try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf + try test__truncsfhf2(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__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 + try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 + + try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 + try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 + + try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 + try test__truncsfhf2(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__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 + try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 + + try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 + try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 + + try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 + + try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 + try test__truncsfhf2(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__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 + try test__truncsfhf2(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 +} + +const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; + +fn test__truncdfhf2(a: f64, expected: u16) void { + const rep = @bitCast(u16, __truncdfhf2(a)); + + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7e00) { + if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { + return; + } + } + + @panic("__truncdfhf2 test failure"); +} + +fn test__truncdfhf2_raw(a: u64, expected: u16) void { + const actual = @bitCast(u16, __truncdfhf2(@bitCast(f64, a))); + + if (actual == expected) { + return; + } + + @panic("__truncdfhf2 test failure"); +} + +test "truncdfhf2" { + test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN + test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN + + test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf + test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf + + test__truncdfhf2(0.0, 0x0); // zero + test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero + + test__truncdfhf2(3.1415926535, 0x4248); + test__truncdfhf2(-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); + + // 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); + + // and back to zero + test__truncdfhf2(0x1.0p-25, 0x0000); + test__truncdfhf2(-0x1.0p-25, 0x8000); + + // max (precise) + test__truncdfhf2(65504.0, 0x7bff); + + // max (rounded) + test__truncdfhf2(65519.0, 0x7bff); + + // max (to +inf) + test__truncdfhf2(65520.0, 0x7c00); + test__truncdfhf2(-65520.0, 0xfc00); + test__truncdfhf2(65536.0, 0x7c00); +} + +const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; + +fn test__trunctfsf2(a: f128, expected: u32) void { + const x = __trunctfsf2(a); + + const rep = @bitCast(u32, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7fc00000) { + if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { + return; + } + } + + @panic("__trunctfsf2 test failure"); +} + +test "trunctfsf2" { + // qnan + test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); + // nan + test__trunctfsf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); + // inf + test__trunctfsf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7f800000); + // zero + test__trunctfsf2(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); +} + +const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2; + +fn test__trunctfdf2(a: f128, expected: u64) void { + const x = __trunctfdf2(a); + + const rep = @bitCast(u64, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7ff8000000000000) { + if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { + return; + } + } + + @panic("__trunctfsf2 test failure"); +} + +test "trunctfdf2" { + // qnan + test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); + // nan + test__trunctfdf2(@bitCast(f128, @as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); + // inf + test__trunctfdf2(@bitCast(f128, @as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); + // zero + test__trunctfdf2(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); +} + +const __truncdfsf2 = @import("truncXfYf2.zig").__truncdfsf2; + +fn test__truncdfsf2(a: f64, expected: u32) void { + const x = __truncdfsf2(a); + + const rep = @bitCast(u32, x); + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7fc00000) { + if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { + return; + } + } + + std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); + + @panic("__trunctfsf2 test failure"); +} + +test "truncdfsf2" { + // nan & qnan + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff8000000000000)), 0x7fc00000); + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000001)), 0x7fc00000); + // inf + test__truncdfsf2(@bitCast(f64, @as(u64, 0x7ff0000000000000)), 0x7f800000); + test__truncdfsf2(@bitCast(f64, @as(u64, 0xfff0000000000000)), 0xff800000); + + test__truncdfsf2(0.0, 0x0); + test__truncdfsf2(1.0, 0x3f800000); + test__truncdfsf2(-1.0, 0xbf800000); + + // huge number becomes inf + test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); +} + +const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; + +fn test__trunctfhf2(a: f128, expected: u16) void { + const x = __trunctfhf2(a); + + const rep = @bitCast(u16, x); + if (rep == expected) { + return; + } + + std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); + + @panic("__trunctfhf2 test failure"); +} + +test "trunctfhf2" { + // qNaN + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); + // NaN + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); + // inf + test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); + test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00); + // zero + test__trunctfhf2(0.0, 0x0); + test__trunctfhf2(-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); + // 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); + // and back to zero + test__trunctfhf2(0x1.0p-25, 0x0000); + test__trunctfhf2(-0x1.0p-25, 0x8000); + // max (precise) + test__trunctfhf2(65504.0, 0x7bff); + // max (rounded) + test__trunctfhf2(65519.0, 0x7bff); + // max (to +inf) + test__trunctfhf2(65520.0, 0x7c00); + test__trunctfhf2(65536.0, 0x7c00); + test__trunctfhf2(-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); +} + +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); + try testing.expect(x == expected); +} diff --git a/lib/compiler_rt/truncsfhf2.zig b/lib/compiler_rt/truncsfhf2.zig new file mode 100644 index 0000000000..5fe0f329b6 --- /dev/null +++ b/lib/compiler_rt/truncsfhf2.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_gnu_abi) { + @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = common.linkage }); + } else if (common.want_aeabi) { + @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage }); + } else { + @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage }); + } +} + +fn __truncsfhf2(a: f32) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} + +fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} + +fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { + return @bitCast(common.F16T, truncf(f16, f32, a)); +} diff --git a/lib/compiler_rt/trunctfdf2.zig b/lib/compiler_rt/trunctfdf2.zig new file mode 100644 index 0000000000..012de610c3 --- /dev/null +++ b/lib/compiler_rt/trunctfdf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = common.linkage }); + } else { + @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = common.linkage }); + } +} + +fn __trunctfdf2(a: f128) callconv(.C) f64 { + return truncf(f64, f128, a); +} + +fn __trunckfdf2(a: f128) callconv(.C) f64 { + return truncf(f64, f128, a); +} diff --git a/lib/compiler_rt/trunctfhf2.zig b/lib/compiler_rt/trunctfhf2.zig new file mode 100644 index 0000000000..a81cc138f1 --- /dev/null +++ b/lib/compiler_rt/trunctfhf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + @export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = common.linkage }); +} + +fn __trunctfhf2(a: f128) callconv(.C) common.F16T { + return @bitCast(common.F16T, truncf(f16, f128, a)); +} diff --git a/lib/compiler_rt/trunctfsf2.zig b/lib/compiler_rt/trunctfsf2.zig new file mode 100644 index 0000000000..535f73e473 --- /dev/null +++ b/lib/compiler_rt/trunctfsf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const truncf = @import("./truncf.zig").truncf; + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = common.linkage }); + } else { + @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = common.linkage }); + } +} + +fn __trunctfsf2(a: f128) callconv(.C) f32 { + return truncf(f32, f128, a); +} + +fn __trunckfsf2(a: f128) callconv(.C) f32 { + return truncf(f32, f128, a); +} diff --git a/lib/compiler_rt/trunctfxf2.zig b/lib/compiler_rt/trunctfxf2.zig new file mode 100644 index 0000000000..0cb7f86a1f --- /dev/null +++ b/lib/compiler_rt/trunctfxf2.zig @@ -0,0 +1,66 @@ +const math = @import("std").math; +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage }); +} + +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 = @bitCast(u128, 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 |= @truncate(u64, 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 = @truncate(u64, a_abs >> (src_sig_bits - dst_sig_bits)) | integer_bit; + res.exp = @truncate(u16, a_abs >> src_sig_bits); + + const round_bits = a_abs & round_mask; + if (round_bits > halfway) { + // Round to nearest + const carry = @boolToInt(@addWithOverflow(u64, res.fraction, 1, &res.fraction)); + res.exp += carry; + res.fraction |= @as(u64, carry) << 63; // Restore integer bit after carry + } else if (round_bits == halfway) { + // Ties to even + const carry = @boolToInt(@addWithOverflow(u64, res.fraction, res.fraction & 1, &res.fraction)); + res.exp += carry; + res.fraction |= @as(u64, carry) << 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 math.make_f80(res); +} diff --git a/lib/compiler_rt/truncxfdf2.zig b/lib/compiler_rt/truncxfdf2.zig new file mode 100644 index 0000000000..2b8eaaab8c --- /dev/null +++ b/lib/compiler_rt/truncxfdf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfdf2, .{ .name = "__truncxfdf2", .linkage = common.linkage }); +} + +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 new file mode 100644 index 0000000000..75fdd17841 --- /dev/null +++ b/lib/compiler_rt/truncxfhf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfhf2, .{ .name = "__truncxfhf2", .linkage = common.linkage }); +} + +fn __truncxfhf2(a: f80) callconv(.C) common.F16T { + return @bitCast(common.F16T, trunc_f80(f16, a)); +} diff --git a/lib/compiler_rt/truncxfsf2.zig b/lib/compiler_rt/truncxfsf2.zig new file mode 100644 index 0000000000..57c0cb7bdf --- /dev/null +++ b/lib/compiler_rt/truncxfsf2.zig @@ -0,0 +1,12 @@ +const common = @import("./common.zig"); +const trunc_f80 = @import("./truncf.zig").trunc_f80; + +pub const panic = common.panic; + +comptime { + @export(__truncxfsf2, .{ .name = "__truncxfsf2", .linkage = common.linkage }); +} + +fn __truncxfsf2(a: f80) callconv(.C) f32 { + return trunc_f80(f32, a); +} diff --git a/lib/compiler_rt/unorddf2.zig b/lib/compiler_rt/unorddf2.zig new file mode 100644 index 0000000000..a6538f99d5 --- /dev/null +++ b/lib/compiler_rt/unorddf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = common.linkage }); + } else { + @export(__unorddf2, .{ .name = "__unorddf2", .linkage = common.linkage }); + } +} + +fn __unorddf2(a: f64, b: f64) callconv(.C) i32 { + return comparef.unordcmp(f64, a, b); +} + +fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 { + return comparef.unordcmp(f64, a, b); +} diff --git a/lib/compiler_rt/unordsf2.zig b/lib/compiler_rt/unordsf2.zig new file mode 100644 index 0000000000..1dc7eb178e --- /dev/null +++ b/lib/compiler_rt/unordsf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_aeabi) { + @export(__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = common.linkage }); + } else { + @export(__unordsf2, .{ .name = "__unordsf2", .linkage = common.linkage }); + } +} + +fn __unordsf2(a: f32, b: f32) callconv(.C) i32 { + return comparef.unordcmp(f32, a, b); +} + +fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 { + return comparef.unordcmp(f32, a, b); +} diff --git a/lib/compiler_rt/unordtf2.zig b/lib/compiler_rt/unordtf2.zig new file mode 100644 index 0000000000..833d6d6cee --- /dev/null +++ b/lib/compiler_rt/unordtf2.zig @@ -0,0 +1,20 @@ +const common = @import("./common.zig"); +const comparef = @import("./comparef.zig"); + +pub const panic = common.panic; + +comptime { + if (common.want_ppc_abi) { + @export(__unordkf2, .{ .name = "__unordkf2", .linkage = common.linkage }); + } else { + @export(__unordtf2, .{ .name = "__unordtf2", .linkage = common.linkage }); + } +} + +fn __unordtf2(a: f128, b: f128) callconv(.C) i32 { + return comparef.unordcmp(f128, a, b); +} + +fn __unordkf2(a: f128, b: f128) callconv(.C) i32 { + return comparef.unordcmp(f128, a, b); +} diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 5149ce192f..3418886a42 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -200,8 +200,8 @@ const sources = &[_][]const u8{ "compiler_rt/umodti3.zig", "compiler_rt/truncXfYf2.zig", "compiler_rt/trunc_f80.zig", - "compiler_rt/addXf3.zig", - "compiler_rt/mulXf3.zig", + "compiler_rt/addf3.zig", + "compiler_rt/mulf3.zig", "compiler_rt/divsf3.zig", "compiler_rt/divdf3.zig", "compiler_rt/divxf3.zig", -- cgit v1.2.3 From 25671f5a973c209bdf75f8be567cc5e441a865cb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 14:18:08 -0700 Subject: compiler-rt: move SPARC functions into appropriate compilation units --- CMakeLists.txt | 1 - lib/compiler_rt.zig | 2 - lib/compiler_rt/addtf3.zig | 6 ++ lib/compiler_rt/cmptf2.zig | 49 +++++++++++++ lib/compiler_rt/common.zig | 1 + lib/compiler_rt/divtf3.zig | 31 +++++---- lib/compiler_rt/extenddftf2.zig | 7 ++ lib/compiler_rt/extendsftf2.zig | 6 ++ lib/compiler_rt/fixtfdi.zig | 6 ++ lib/compiler_rt/fixtfsi.zig | 6 ++ lib/compiler_rt/fixunstfdi.zig | 6 ++ lib/compiler_rt/fixunstfsi.zig | 6 ++ lib/compiler_rt/floatditf.zig | 6 ++ lib/compiler_rt/floatsitf.zig | 6 ++ lib/compiler_rt/floatunditf.zig | 6 ++ lib/compiler_rt/floatunsitf.zig | 6 ++ lib/compiler_rt/getf2.zig | 3 + lib/compiler_rt/multf3.zig | 6 ++ lib/compiler_rt/sparc.zig | 148 ---------------------------------------- lib/compiler_rt/subtf3.zig | 13 +++- lib/compiler_rt/trunctfdf2.zig | 6 ++ lib/compiler_rt/trunctfsf2.zig | 6 ++ lib/compiler_rt/unordtf2.zig | 3 + src/compiler_rt.zig | 1 - 24 files changed, 170 insertions(+), 167 deletions(-) delete mode 100644 lib/compiler_rt/sparc.zig (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index a393249458..2a92a40dc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -619,7 +619,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/compiler_rt/shift.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sin.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sincos.zig" - "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sparc.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sqrt.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig" "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig" diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 826530286d..5f199e9eae 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -179,6 +179,4 @@ comptime { _ = @import("compiler_rt/aulldiv.zig"); _ = @import("compiler_rt/aullrem.zig"); _ = @import("compiler_rt/clear_cache.zig"); - - _ = @import("compiler_rt/sparc.zig"); } diff --git a/lib/compiler_rt/addtf3.zig b/lib/compiler_rt/addtf3.zig index 40a6e6c8b7..f7c33ba969 100644 --- a/lib/compiler_rt/addtf3.zig +++ b/lib/compiler_rt/addtf3.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__addkf3, .{ .name = "__addkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_add, .{ .name = "_Qp_add", .linkage = common.linkage }); } else { @export(__addtf3, .{ .name = "__addtf3", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __addtf3(a: f128, b: f128) callconv(.C) f128 { fn __addkf3(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/cmptf2.zig b/lib/compiler_rt/cmptf2.zig index 86dc68ad56..00263f943a 100644 --- a/lib/compiler_rt/cmptf2.zig +++ b/lib/compiler_rt/cmptf2.zig @@ -11,6 +11,14 @@ comptime { @export(__nekf2, .{ .name = "__nekf2", .linkage = common.linkage }); @export(__ltkf2, .{ .name = "__ltkf2", .linkage = common.linkage }); @export(__lekf2, .{ .name = "__lekf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = common.linkage }); + @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = common.linkage }); + @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = common.linkage }); + @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = common.linkage }); + @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = common.linkage }); + @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = common.linkage }); + @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = common.linkage }); } else { @export(__eqtf2, .{ .name = "__eqtf2", .linkage = common.linkage }); @export(__netf2, .{ .name = "__netf2", .linkage = common.linkage }); @@ -71,3 +79,44 @@ fn __ltkf2(a: f128, b: f128) callconv(.C) i32 { fn __lekf2(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 @enumToInt(comparef.cmpf2(f128, SparcFCMP, a.*, b.*)); +} + +fn _Qp_feq(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Equal; +} + +fn _Qp_fne(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) != .Equal; +} + +fn _Qp_flt(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Less; +} + +fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.C) bool { + return @intToEnum(SparcFCMP, _Qp_cmp(a, b)) == .Greater; +} + +fn _Qp_fge(a: *const f128, b: *const f128) callconv(.C) bool { + return switch (@intToEnum(SparcFCMP, _Qp_cmp(a, b))) { + .Equal, .Greater => true, + .Less, .Unordered => false, + }; +} + +fn _Qp_fle(a: *const f128, b: *const f128) callconv(.C) bool { + return switch (@intToEnum(SparcFCMP, _Qp_cmp(a, b))) { + .Equal, .Less => true, + .Greater, .Unordered => false, + }; +} diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 196dc33024..b1462d21c1 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -8,6 +8,7 @@ pub const want_aeabi = builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb(); pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); pub const want_msvc_abi = builtin.abi == .msvc; pub const want_gnu_abi = builtin.abi.isGnu(); +pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); // Avoid dragging in the runtime safety mechanisms into this .o file, // unless we're trying to test compiler-rt. diff --git a/lib/compiler_rt/divtf3.zig b/lib/compiler_rt/divtf3.zig index 436db41dc2..66e01e1843 100644 --- a/lib/compiler_rt/divtf3.zig +++ b/lib/compiler_rt/divtf3.zig @@ -1,30 +1,35 @@ const std = @import("std"); const builtin = @import("builtin"); -const arch = builtin.cpu.arch; -const is_test = builtin.is_test; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; const common = @import("common.zig"); const normalize = common.normalize; const wideMultiply = common.wideMultiply; + pub const panic = common.panic; comptime { - @export(__divtf3, .{ .name = "__divtf3", .linkage = linkage }); - - if (!is_test) { - if (arch.isPPC() or arch.isPPC64()) { - @export(__divkf3, .{ .name = "__divkf3", .linkage = linkage }); - } + if (common.want_ppc_abi) { + @export(__divkf3, .{ .name = "__divkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_div, .{ .name = "_Qp_div", .linkage = common.linkage }); + } else { + @export(__divtf3, .{ .name = "__divtf3", .linkage = common.linkage }); } } -pub fn __divkf3(a: f128, b: f128) callconv(.C) f128 { - return @call(.{ .modifier = .always_inline }, __divtf3, .{ a, b }); +fn __divkf3(a: f128, b: f128) callconv(.C) f128 { + return div(a, b); +} + +fn _Qp_div(c: *f128, a: *const f128, b: *const f128) callconv(.C) void { + c.* = div(a.*, b.*); +} + +fn __divtf3(a: f128, b: f128) callconv(.C) f128 { + return div(a, b); } -pub fn __divtf3(a: f128, b: f128) callconv(.C) f128 { - @setRuntimeSafety(builtin.is_test); +inline fn div(a: f128, b: f128) f128 { const Z = std.meta.Int(.unsigned, 128); const significandBits = std.math.floatMantissaBits(f128); diff --git a/lib/compiler_rt/extenddftf2.zig b/lib/compiler_rt/extenddftf2.zig index c957d64a63..fa0053ad5c 100644 --- a/lib/compiler_rt/extenddftf2.zig +++ b/lib/compiler_rt/extenddftf2.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__extenddfkf2, .{ .name = "__extenddfkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = common.linkage }); } else { @export(__extenddftf2, .{ .name = "__extenddftf2", .linkage = common.linkage }); } @@ -18,3 +20,8 @@ fn __extenddftf2(a: f64) callconv(.C) f128 { fn __extenddfkf2(a: f64) callconv(.C) f128 { return extendf(f128, f64, @bitCast(u64, a)); } + +fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void { + c.* = @import("extendXfYf2.zig").__extenddftf2(a); + c.* = extendf(f128, f64, @bitCast(u64, a)); +} diff --git a/lib/compiler_rt/extendsftf2.zig b/lib/compiler_rt/extendsftf2.zig index 8b496783c8..a3b29802e6 100644 --- a/lib/compiler_rt/extendsftf2.zig +++ b/lib/compiler_rt/extendsftf2.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__extendsfkf2, .{ .name = "__extendsfkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = common.linkage }); } else { @export(__extendsftf2, .{ .name = "__extendsftf2", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __extendsftf2(a: f32) callconv(.C) f128 { fn __extendsfkf2(a: f32) callconv(.C) f128 { return extendf(f128, f32, @bitCast(u32, a)); } + +fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void { + c.* = extendf(f128, f32, @bitCast(u32, a)); +} diff --git a/lib/compiler_rt/fixtfdi.zig b/lib/compiler_rt/fixtfdi.zig index 8f8d473b1f..20bc4d89d6 100644 --- a/lib/compiler_rt/fixtfdi.zig +++ b/lib/compiler_rt/fixtfdi.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__fixkfdi, .{ .name = "__fixkfdi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = common.linkage }); } else { @export(__fixtfdi, .{ .name = "__fixtfdi", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __fixtfdi(a: f128) callconv(.C) i64 { fn __fixkfdi(a: f128) callconv(.C) i64 { return floatToInt(i64, a); } + +fn _Qp_qtox(a: *const f128) callconv(.C) i64 { + return floatToInt(i64, a.*); +} diff --git a/lib/compiler_rt/fixtfsi.zig b/lib/compiler_rt/fixtfsi.zig index 507581d0cf..44cac245fb 100644 --- a/lib/compiler_rt/fixtfsi.zig +++ b/lib/compiler_rt/fixtfsi.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__fixkfsi, .{ .name = "__fixkfsi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = common.linkage }); } else { @export(__fixtfsi, .{ .name = "__fixtfsi", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __fixtfsi(a: f128) callconv(.C) i32 { fn __fixkfsi(a: f128) callconv(.C) i32 { return floatToInt(i32, a); } + +fn _Qp_qtoi(a: *const f128) callconv(.C) i32 { + return floatToInt(i32, a.*); +} diff --git a/lib/compiler_rt/fixunstfdi.zig b/lib/compiler_rt/fixunstfdi.zig index 0130f21139..f8b9aa7ac4 100644 --- a/lib/compiler_rt/fixunstfdi.zig +++ b/lib/compiler_rt/fixunstfdi.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__fixunskfdi, .{ .name = "__fixunskfdi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = common.linkage }); } else { @export(__fixunstfdi, .{ .name = "__fixunstfdi", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __fixunstfdi(a: f128) callconv(.C) u64 { fn __fixunskfdi(a: f128) callconv(.C) u64 { return floatToInt(u64, a); } + +fn _Qp_qtoux(a: *const f128) callconv(.C) u64 { + return floatToInt(u64, a.*); +} diff --git a/lib/compiler_rt/fixunstfsi.zig b/lib/compiler_rt/fixunstfsi.zig index 78e2cc83d4..64f70af649 100644 --- a/lib/compiler_rt/fixunstfsi.zig +++ b/lib/compiler_rt/fixunstfsi.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__fixunskfsi, .{ .name = "__fixunskfsi", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = common.linkage }); } else { @export(__fixunstfsi, .{ .name = "__fixunstfsi", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __fixunstfsi(a: f128) callconv(.C) u32 { fn __fixunskfsi(a: f128) callconv(.C) u32 { return floatToInt(u32, a); } + +fn _Qp_qtoui(a: *const f128) callconv(.C) u32 { + return floatToInt(u32, a.*); +} diff --git a/lib/compiler_rt/floatditf.zig b/lib/compiler_rt/floatditf.zig index 04132b9c24..eb1ce3337b 100644 --- a/lib/compiler_rt/floatditf.zig +++ b/lib/compiler_rt/floatditf.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__floatdikf, .{ .name = "__floatdikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = common.linkage }); } else { @export(__floatditf, .{ .name = "__floatditf", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __floatditf(a: i64) callconv(.C) f128 { fn __floatdikf(a: i64) callconv(.C) f128 { return intToFloat(f128, a); } + +fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatsitf.zig b/lib/compiler_rt/floatsitf.zig index 24f5e3bf42..0f43800436 100644 --- a/lib/compiler_rt/floatsitf.zig +++ b/lib/compiler_rt/floatsitf.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__floatsikf, .{ .name = "__floatsikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = common.linkage }); } else { @export(__floatsitf, .{ .name = "__floatsitf", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __floatsitf(a: i32) callconv(.C) f128 { fn __floatsikf(a: i32) callconv(.C) f128 { return intToFloat(f128, a); } + +fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatunditf.zig b/lib/compiler_rt/floatunditf.zig index 40424d1a6c..ed752e40c2 100644 --- a/lib/compiler_rt/floatunditf.zig +++ b/lib/compiler_rt/floatunditf.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__floatundikf, .{ .name = "__floatundikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = common.linkage }); } else { @export(__floatunditf, .{ .name = "__floatunditf", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __floatunditf(a: u64) callconv(.C) f128 { fn __floatundikf(a: u64) callconv(.C) f128 { return intToFloat(f128, a); } + +fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/floatunsitf.zig b/lib/compiler_rt/floatunsitf.zig index 3f626324d2..54d099c82a 100644 --- a/lib/compiler_rt/floatunsitf.zig +++ b/lib/compiler_rt/floatunsitf.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__floatunsikf, .{ .name = "__floatunsikf", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = common.linkage }); } else { @export(__floatunsitf, .{ .name = "__floatunsitf", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __floatunsitf(a: u32) callconv(.C) f128 { fn __floatunsikf(a: u32) callconv(.C) f128 { return intToFloat(f128, a); } + +fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void { + c.* = intToFloat(f128, a); +} diff --git a/lib/compiler_rt/getf2.zig b/lib/compiler_rt/getf2.zig index 402d9ad391..8d9d39c1f9 100644 --- a/lib/compiler_rt/getf2.zig +++ b/lib/compiler_rt/getf2.zig @@ -9,6 +9,9 @@ comptime { if (common.want_ppc_abi) { @export(__gekf2, .{ .name = "__gekf2", .linkage = common.linkage }); @export(__gtkf2, .{ .name = "__gtkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + // These exports are handled in cmptf2.zig because gt and ge on sparc + // are based on calling _Qp_cmp. } else { @export(__getf2, .{ .name = "__getf2", .linkage = common.linkage }); @export(__gttf2, .{ .name = "__gttf2", .linkage = common.linkage }); diff --git a/lib/compiler_rt/multf3.zig b/lib/compiler_rt/multf3.zig index f71867c9ca..b18f5912a5 100644 --- a/lib/compiler_rt/multf3.zig +++ b/lib/compiler_rt/multf3.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__mulkf3, .{ .name = "__mulkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = common.linkage }); } else { @export(__multf3, .{ .name = "__multf3", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __multf3(a: f128, b: f128) callconv(.C) f128 { fn __mulkf3(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/sparc.zig b/lib/compiler_rt/sparc.zig deleted file mode 100644 index a39951a1c8..0000000000 --- a/lib/compiler_rt/sparc.zig +++ /dev/null @@ -1,148 +0,0 @@ -// -// SPARC uses a different naming scheme for its support routines so we map it here to the x86 name. - -const std = @import("std"); -const builtin = @import("builtin"); -const arch = builtin.cpu.arch; -const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; -pub const panic = @import("common.zig").panic; - -comptime { - if (arch.isSPARC()) { - // SPARC systems use a different naming scheme - @export(_Qp_add, .{ .name = "_Qp_add", .linkage = linkage }); - @export(_Qp_div, .{ .name = "_Qp_div", .linkage = linkage }); - @export(_Qp_mul, .{ .name = "_Qp_mul", .linkage = linkage }); - @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = linkage }); - - @export(_Qp_cmp, .{ .name = "_Qp_cmp", .linkage = linkage }); - @export(_Qp_feq, .{ .name = "_Qp_feq", .linkage = linkage }); - @export(_Qp_fne, .{ .name = "_Qp_fne", .linkage = linkage }); - @export(_Qp_flt, .{ .name = "_Qp_flt", .linkage = linkage }); - @export(_Qp_fle, .{ .name = "_Qp_fle", .linkage = linkage }); - @export(_Qp_fgt, .{ .name = "_Qp_fgt", .linkage = linkage }); - @export(_Qp_fge, .{ .name = "_Qp_fge", .linkage = linkage }); - - @export(_Qp_itoq, .{ .name = "_Qp_itoq", .linkage = linkage }); - @export(_Qp_uitoq, .{ .name = "_Qp_uitoq", .linkage = linkage }); - @export(_Qp_xtoq, .{ .name = "_Qp_xtoq", .linkage = linkage }); - @export(_Qp_uxtoq, .{ .name = "_Qp_uxtoq", .linkage = linkage }); - @export(_Qp_stoq, .{ .name = "_Qp_stoq", .linkage = linkage }); - @export(_Qp_dtoq, .{ .name = "_Qp_dtoq", .linkage = linkage }); - @export(_Qp_qtoi, .{ .name = "_Qp_qtoi", .linkage = linkage }); - @export(_Qp_qtoui, .{ .name = "_Qp_qtoui", .linkage = linkage }); - @export(_Qp_qtox, .{ .name = "_Qp_qtox", .linkage = linkage }); - @export(_Qp_qtoux, .{ .name = "_Qp_qtoux", .linkage = linkage }); - @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = linkage }); - @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage }); - } -} - -// The SPARC Architecture Manual, Version 9: -// A.13 Floating-Point Compare -const FCMP = enum(i32) { - Equal = 0, - Less = 1, - Greater = 2, - Unordered = 3, -}; - -// Basic arithmetic - -pub fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addf3.zig").__addtf3(a.*, b.*); -} - -pub fn _Qp_div(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("divtf3.zig").__divtf3(a.*, b.*); -} - -pub fn _Qp_mul(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("mulf3.zig").__multf3(a.*, b.*); -} - -pub fn _Qp_sub(c: *f128, a: *f128, b: *f128) callconv(.C) void { - c.* = @import("addf3.zig").__subtf3(a.*, b.*); -} - -// Comparison - -pub fn _Qp_cmp(a: *f128, b: *f128) callconv(.C) i32 { - return @enumToInt(@import("compareXf2.zig").cmp(f128, FCMP, a.*, b.*)); -} - -pub fn _Qp_feq(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Equal); -} - -pub fn _Qp_fne(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) != @enumToInt(FCMP.Equal); -} - -pub fn _Qp_flt(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Less); -} - -pub fn _Qp_fle(a: *f128, b: *f128) callconv(.C) bool { - const cmp = _Qp_cmp(a, b); - return cmp == @enumToInt(FCMP.Less) or cmp == @enumToInt(FCMP.Equal); -} - -pub fn _Qp_fgt(a: *f128, b: *f128) callconv(.C) bool { - return _Qp_cmp(a, b) == @enumToInt(FCMP.Greater); -} - -pub fn _Qp_fge(a: *f128, b: *f128) callconv(.C) bool { - const cmp = _Qp_cmp(a, b); - return cmp == @enumToInt(FCMP.Greater) or cmp == @enumToInt(FCMP.Equal); -} - -// Conversion - -pub fn _Qp_itoq(c: *f128, a: i32) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatsitf(a); -} - -pub fn _Qp_uitoq(c: *f128, a: u32) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatunsitf(a); -} - -pub fn _Qp_xtoq(c: *f128, a: i64) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatditf(a); -} - -pub fn _Qp_uxtoq(c: *f128, a: u64) callconv(.C) void { - c.* = @import("floatXiYf.zig").__floatunditf(a); -} - -pub fn _Qp_stoq(c: *f128, a: f32) callconv(.C) void { - c.* = @import("extendXfYf2.zig").__extendsftf2(a); -} - -pub fn _Qp_dtoq(c: *f128, a: f64) callconv(.C) void { - c.* = @import("extendXfYf2.zig").__extenddftf2(a); -} - -pub fn _Qp_qtoi(a: *f128) callconv(.C) i32 { - return @import("fixXfYi.zig").__fixtfsi(a.*); -} - -pub fn _Qp_qtoui(a: *f128) callconv(.C) u32 { - return @import("fixXfYi.zig").__fixunstfsi(a.*); -} - -pub fn _Qp_qtox(a: *f128) callconv(.C) i64 { - return @import("fixXfYi.zig").__fixtfdi(a.*); -} - -pub fn _Qp_qtoux(a: *f128) callconv(.C) u64 { - return @import("fixXfYi.zig").__fixunstfdi(a.*); -} - -pub fn _Qp_qtos(a: *f128) callconv(.C) f32 { - return @import("truncXfYf2.zig").__trunctfsf2(a.*); -} - -pub fn _Qp_qtod(a: *f128) callconv(.C) f64 { - return @import("truncXfYf2.zig").__trunctfdf2(a.*); -} diff --git a/lib/compiler_rt/subtf3.zig b/lib/compiler_rt/subtf3.zig index a4e2f4dfae..aa50f73da8 100644 --- a/lib/compiler_rt/subtf3.zig +++ b/lib/compiler_rt/subtf3.zig @@ -5,17 +5,26 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__subkf3, .{ .name = "__subkf3", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_sub, .{ .name = "_Qp_sub", .linkage = common.linkage }); } else { @export(__subtf3, .{ .name = "__subtf3", .linkage = common.linkage }); } } fn __subtf3(a: f128, b: f128) callconv(.C) f128 { - const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); - return a + neg_b; + return sub(a, b); } fn __subkf3(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 = @bitCast(f128, @bitCast(u128, b) ^ (@as(u128, 1) << 127)); return a + neg_b; } diff --git a/lib/compiler_rt/trunctfdf2.zig b/lib/compiler_rt/trunctfdf2.zig index 012de610c3..3fe16ad6a2 100644 --- a/lib/compiler_rt/trunctfdf2.zig +++ b/lib/compiler_rt/trunctfdf2.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__trunckfdf2, .{ .name = "__trunckfdf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtod, .{ .name = "_Qp_qtod", .linkage = common.linkage }); } else { @export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __trunctfdf2(a: f128) callconv(.C) f64 { fn __trunckfdf2(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/trunctfsf2.zig b/lib/compiler_rt/trunctfsf2.zig index 535f73e473..f507f5ad2b 100644 --- a/lib/compiler_rt/trunctfsf2.zig +++ b/lib/compiler_rt/trunctfsf2.zig @@ -6,6 +6,8 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__trunckfsf2, .{ .name = "__trunckfsf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + @export(_Qp_qtos, .{ .name = "_Qp_qtos", .linkage = common.linkage }); } else { @export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = common.linkage }); } @@ -18,3 +20,7 @@ fn __trunctfsf2(a: f128) callconv(.C) f32 { fn __trunckfsf2(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/unordtf2.zig b/lib/compiler_rt/unordtf2.zig index 833d6d6cee..41d1d7008e 100644 --- a/lib/compiler_rt/unordtf2.zig +++ b/lib/compiler_rt/unordtf2.zig @@ -6,6 +6,9 @@ pub const panic = common.panic; comptime { if (common.want_ppc_abi) { @export(__unordkf2, .{ .name = "__unordkf2", .linkage = common.linkage }); + } else if (common.want_sparc_abi) { + // These exports are handled in cmptf2.zig because unordered comparisons + // are based on calling _Qp_cmp. } else { @export(__unordtf2, .{ .name = "__unordtf2", .linkage = common.linkage }); } diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 3418886a42..ee0fc75fc5 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -228,6 +228,5 @@ const sources = &[_][]const u8{ "compiler_rt/arm.zig", "compiler_rt/aulldiv.zig", "compiler_rt/aullrem.zig", - "compiler_rt/sparc.zig", "compiler_rt/clear_cache.zig", }; -- cgit v1.2.3 From 4200f89d94b8b917f3429e11ef11f136fa910ca9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 15:14:24 -0700 Subject: compiler-rt: sort source files --- src/compiler_rt.zig | 84 ++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index ee0fc75fc5..5967da9cff 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -168,65 +168,65 @@ pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *?CRTFile) !void } const sources = &[_][]const u8{ + "compiler_rt/absv.zig", + "compiler_rt/addf3.zig", + "compiler_rt/addo.zig", + "compiler_rt/arm.zig", "compiler_rt/atomics.zig", - "compiler_rt/sin.zig", - "compiler_rt/cos.zig", - "compiler_rt/sincos.zig", + "compiler_rt/aulldiv.zig", + "compiler_rt/aullrem.zig", + "compiler_rt/bswap.zig", "compiler_rt/ceil.zig", + "compiler_rt/clear_cache.zig", + "compiler_rt/cmp.zig", + "compiler_rt/compareXf2.zig", + "compiler_rt/cos.zig", + "compiler_rt/count0bits.zig", + "compiler_rt/divdf3.zig", + "compiler_rt/divsf3.zig", + "compiler_rt/divtf3.zig", + "compiler_rt/divti3.zig", + "compiler_rt/divxf3.zig", + "compiler_rt/emutls.zig", "compiler_rt/exp.zig", "compiler_rt/exp2.zig", + "compiler_rt/extendXfYf2.zig", + "compiler_rt/extend_f80.zig", "compiler_rt/fabs.zig", + "compiler_rt/fixXfYi.zig", + "compiler_rt/floatXiYf.zig", "compiler_rt/floor.zig", "compiler_rt/fma.zig", "compiler_rt/fmax.zig", "compiler_rt/fmin.zig", "compiler_rt/fmod.zig", + "compiler_rt/int.zig", "compiler_rt/log.zig", "compiler_rt/log10.zig", "compiler_rt/log2.zig", - "compiler_rt/round.zig", - "compiler_rt/sqrt.zig", - "compiler_rt/tan.zig", - "compiler_rt/trunc.zig", - "compiler_rt/extendXfYf2.zig", - "compiler_rt/extend_f80.zig", - "compiler_rt/compareXf2.zig", - "compiler_rt/stack_probe.zig", - "compiler_rt/divti3.zig", "compiler_rt/modti3.zig", - "compiler_rt/multi3.zig", - "compiler_rt/udivti3.zig", - "compiler_rt/udivmodti4.zig", - "compiler_rt/umodti3.zig", - "compiler_rt/truncXfYf2.zig", - "compiler_rt/trunc_f80.zig", - "compiler_rt/addf3.zig", + "compiler_rt/muldi3.zig", "compiler_rt/mulf3.zig", - "compiler_rt/divsf3.zig", - "compiler_rt/divdf3.zig", - "compiler_rt/divxf3.zig", - "compiler_rt/divtf3.zig", - "compiler_rt/floatXiYf.zig", - "compiler_rt/fixXfYi.zig", - "compiler_rt/count0bits.zig", + "compiler_rt/mulo.zig", + "compiler_rt/multi3.zig", + "compiler_rt/negXf2.zig", + "compiler_rt/negXi2.zig", + "compiler_rt/negv.zig", + "compiler_rt/os_version_check.zig", "compiler_rt/parity.zig", "compiler_rt/popcount.zig", - "compiler_rt/bswap.zig", - "compiler_rt/int.zig", + "compiler_rt/round.zig", "compiler_rt/shift.zig", - "compiler_rt/negXi2.zig", - "compiler_rt/muldi3.zig", - "compiler_rt/absv.zig", - "compiler_rt/negv.zig", - "compiler_rt/addo.zig", + "compiler_rt/sin.zig", + "compiler_rt/sincos.zig", + "compiler_rt/sqrt.zig", + "compiler_rt/stack_probe.zig", "compiler_rt/subo.zig", - "compiler_rt/mulo.zig", - "compiler_rt/cmp.zig", - "compiler_rt/negXf2.zig", - "compiler_rt/os_version_check.zig", - "compiler_rt/emutls.zig", - "compiler_rt/arm.zig", - "compiler_rt/aulldiv.zig", - "compiler_rt/aullrem.zig", - "compiler_rt/clear_cache.zig", + "compiler_rt/tan.zig", + "compiler_rt/trunc.zig", + "compiler_rt/truncXfYf2.zig", + "compiler_rt/trunc_f80.zig", + "compiler_rt/udivmodti4.zig", + "compiler_rt/udivti3.zig", + "compiler_rt/umodti3.zig", }; -- cgit v1.2.3 From 453243d9e02a5d893828694e7090515de7777bb8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 15:16:40 -0700 Subject: compiler-rt: correct the list of builtins to build --- src/compiler_rt.zig | 114 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 5967da9cff..0440235d58 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -168,9 +168,14 @@ pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *?CRTFile) !void } const sources = &[_][]const u8{ - "compiler_rt/absv.zig", - "compiler_rt/addf3.zig", + "compiler_rt/absvdi2.zig", + "compiler_rt/absvsi2.zig", + "compiler_rt/absvti2.zig", + "compiler_rt/adddf3.zig", "compiler_rt/addo.zig", + "compiler_rt/addsf3.zig", + "compiler_rt/addtf3.zig", + "compiler_rt/addxf3.zig", "compiler_rt/arm.zig", "compiler_rt/atomics.zig", "compiler_rt/aulldiv.zig", @@ -179,7 +184,10 @@ const sources = &[_][]const u8{ "compiler_rt/ceil.zig", "compiler_rt/clear_cache.zig", "compiler_rt/cmp.zig", - "compiler_rt/compareXf2.zig", + "compiler_rt/cmpdf2.zig", + "compiler_rt/cmpsf2.zig", + "compiler_rt/cmptf2.zig", + "compiler_rt/cmpxf2.zig", "compiler_rt/cos.zig", "compiler_rt/count0bits.zig", "compiler_rt/divdf3.zig", @@ -190,25 +198,98 @@ const sources = &[_][]const u8{ "compiler_rt/emutls.zig", "compiler_rt/exp.zig", "compiler_rt/exp2.zig", - "compiler_rt/extendXfYf2.zig", - "compiler_rt/extend_f80.zig", + "compiler_rt/extenddftf2.zig", + "compiler_rt/extenddfxf2.zig", + "compiler_rt/extendhfsf2.zig", + "compiler_rt/extendhftf2.zig", + "compiler_rt/extendhfxf2.zig", + "compiler_rt/extendsfdf2.zig", + "compiler_rt/extendsftf2.zig", + "compiler_rt/extendsfxf2.zig", + "compiler_rt/extendxftf2.zig", "compiler_rt/fabs.zig", - "compiler_rt/fixXfYi.zig", - "compiler_rt/floatXiYf.zig", + "compiler_rt/fixdfdi.zig", + "compiler_rt/fixdfsi.zig", + "compiler_rt/fixdfti.zig", + "compiler_rt/fixhfdi.zig", + "compiler_rt/fixhfsi.zig", + "compiler_rt/fixhfti.zig", + "compiler_rt/fixsfdi.zig", + "compiler_rt/fixsfsi.zig", + "compiler_rt/fixsfti.zig", + "compiler_rt/fixtfdi.zig", + "compiler_rt/fixtfsi.zig", + "compiler_rt/fixtfti.zig", + "compiler_rt/fixunsdfdi.zig", + "compiler_rt/fixunsdfsi.zig", + "compiler_rt/fixunsdfti.zig", + "compiler_rt/fixunshfdi.zig", + "compiler_rt/fixunshfsi.zig", + "compiler_rt/fixunshfti.zig", + "compiler_rt/fixunssfdi.zig", + "compiler_rt/fixunssfsi.zig", + "compiler_rt/fixunssfti.zig", + "compiler_rt/fixunstfdi.zig", + "compiler_rt/fixunstfsi.zig", + "compiler_rt/fixunstfti.zig", + "compiler_rt/fixunsxfdi.zig", + "compiler_rt/fixunsxfsi.zig", + "compiler_rt/fixunsxfti.zig", + "compiler_rt/fixxfdi.zig", + "compiler_rt/fixxfsi.zig", + "compiler_rt/fixxfti.zig", + "compiler_rt/floatdidf.zig", + "compiler_rt/floatdihf.zig", + "compiler_rt/floatdisf.zig", + "compiler_rt/floatditf.zig", + "compiler_rt/floatdixf.zig", + "compiler_rt/floatsidf.zig", + "compiler_rt/floatsihf.zig", + "compiler_rt/floatsisf.zig", + "compiler_rt/floatsitf.zig", + "compiler_rt/floatsixf.zig", + "compiler_rt/floattidf.zig", + "compiler_rt/floattihf.zig", + "compiler_rt/floattisf.zig", + "compiler_rt/floattitf.zig", + "compiler_rt/floattixf.zig", + "compiler_rt/floatundidf.zig", + "compiler_rt/floatundihf.zig", + "compiler_rt/floatundisf.zig", + "compiler_rt/floatunditf.zig", + "compiler_rt/floatundixf.zig", + "compiler_rt/floatunsidf.zig", + "compiler_rt/floatunsihf.zig", + "compiler_rt/floatunsisf.zig", + "compiler_rt/floatunsitf.zig", + "compiler_rt/floatunsixf.zig", + "compiler_rt/floatuntidf.zig", + "compiler_rt/floatuntihf.zig", + "compiler_rt/floatuntisf.zig", + "compiler_rt/floatuntitf.zig", + "compiler_rt/floatuntixf.zig", "compiler_rt/floor.zig", "compiler_rt/fma.zig", "compiler_rt/fmax.zig", "compiler_rt/fmin.zig", "compiler_rt/fmod.zig", + "compiler_rt/gedf2.zig", + "compiler_rt/gesf2.zig", + "compiler_rt/getf2.zig", + "compiler_rt/gexf2.zig", "compiler_rt/int.zig", "compiler_rt/log.zig", "compiler_rt/log10.zig", "compiler_rt/log2.zig", "compiler_rt/modti3.zig", + "compiler_rt/muldf3.zig", "compiler_rt/muldi3.zig", "compiler_rt/mulf3.zig", "compiler_rt/mulo.zig", + "compiler_rt/mulsf3.zig", + "compiler_rt/multf3.zig", "compiler_rt/multi3.zig", + "compiler_rt/mulxf3.zig", "compiler_rt/negXf2.zig", "compiler_rt/negXi2.zig", "compiler_rt/negv.zig", @@ -221,12 +302,27 @@ const sources = &[_][]const u8{ "compiler_rt/sincos.zig", "compiler_rt/sqrt.zig", "compiler_rt/stack_probe.zig", + "compiler_rt/subdf3.zig", "compiler_rt/subo.zig", + "compiler_rt/subsf3.zig", + "compiler_rt/subtf3.zig", + "compiler_rt/subxf3.zig", "compiler_rt/tan.zig", "compiler_rt/trunc.zig", - "compiler_rt/truncXfYf2.zig", - "compiler_rt/trunc_f80.zig", + "compiler_rt/truncdfhf2.zig", + "compiler_rt/truncdfsf2.zig", + "compiler_rt/truncsfhf2.zig", + "compiler_rt/trunctfdf2.zig", + "compiler_rt/trunctfhf2.zig", + "compiler_rt/trunctfsf2.zig", + "compiler_rt/trunctfxf2.zig", + "compiler_rt/truncxfdf2.zig", + "compiler_rt/truncxfhf2.zig", + "compiler_rt/truncxfsf2.zig", "compiler_rt/udivmodti4.zig", "compiler_rt/udivti3.zig", "compiler_rt/umodti3.zig", + "compiler_rt/unorddf2.zig", + "compiler_rt/unordsf2.zig", + "compiler_rt/unordtf2.zig", }; -- cgit v1.2.3 From fcebdbe25d605f565b22f46ebfb9ca06845926a6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 16:53:40 -0700 Subject: compiler-rt: no more -ffunction-sections --- src/compiler_rt.zig | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 0440235d58..70276231ce 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -113,7 +113,6 @@ pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *?CRTFile) !void .main_pkg = null, .output_mode = .Lib, .link_mode = .Static, - .function_sections = true, .thread_pool = comp.thread_pool, .libc_installation = comp.bin_file.options.libc_installation, .emit_bin = emit_bin, -- cgit v1.2.3 From 5cd548e53081428d0e6b4a6b5a305317052c133a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 20:23:22 -0700 Subject: Compilation: multi-thread compiler-rt compiler_rt_lib and compiler_rt_obj are extracted from the generic JobQueue into simple boolean flags, and then handled explicitly inside performAllTheWork(). Introduced generic handling of allocation failure and made setMiscFailure not return a possible error. Building the compiler-rt static library now takes advantage of Compilation's ThreadPool. This introduced a problem, however, because now each of the object files of compiler-rt all perform AstGen for the full standard library and compiler-rt files. Even though all of them end up being cache hits except for the first ones, this is wasteful - O(N*M) where N is number of compilation units inside compiler-rt and M is the number of .zig files in the standard library and compiler-rt combined. More importantly, however, it causes a deadlock, because each thread interacts with a file system lock for doing AstGen on files, and threads end up waiting for each other. This will need to be handled with a process-level file caching system, or some other creative solution. --- src/Compilation.zig | 193 +++++++++------- src/ThreadPool.zig | 81 ++++--- src/WaitGroup.zig | 7 + src/compiler_rt.zig | 637 +++++++++++++++++++++++++++++----------------------- 4 files changed, 528 insertions(+), 390 deletions(-) (limited to 'src') diff --git a/src/Compilation.zig b/src/Compilation.zig index 2858a28f42..65a2ad92b4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -93,6 +93,9 @@ unwind_tables: bool, test_evented_io: bool, debug_compiler_runtime_libs: bool, debug_compile_errors: bool, +job_queued_compiler_rt_lib: bool = false, +job_queued_compiler_rt_obj: bool = false, +alloc_failure_occurred: bool = false, c_source_files: []const CSourceFile, clang_argv: []const []const u8, @@ -130,11 +133,11 @@ libssp_static_lib: ?CRTFile = null, /// Populated when we build the libc static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libc_static_lib: ?CRTFile = null, -/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue -/// and resolved before calling linker.flush(). +/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated +/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush(). compiler_rt_lib: ?CRTFile = null, -/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue -/// and resolved before calling linker.flush(). +/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated +/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush(). compiler_rt_obj: ?CRTFile = null, glibc_so_files: ?glibc.BuiltSharedObjects = null, @@ -224,8 +227,6 @@ const Job = union(enum) { libcxxabi: void, libtsan: void, libssp: void, - compiler_rt_lib: void, - compiler_rt_obj: void, /// needed when not linking libc and using LLVM for code generation because it generates /// calls to, for example, memcpy and memset. zig_libc: void, @@ -1925,13 +1926,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { if (is_exe_or_dyn_lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); - try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} }); + comp.job_queued_compiler_rt_lib = true; } else if (options.output_mode != .Obj) { log.debug("queuing a job to build compiler_rt_obj", .{}); // If build-obj with -fcompiler-rt is requested, that is handled specially // elsewhere. In this case we are making a static library, so we ask // for a compiler-rt object to put in it. - try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} }); + comp.job_queued_compiler_rt_obj = true; } } if (needs_c_symbols) { @@ -2021,6 +2022,7 @@ pub fn destroy(self: *Compilation) void { } pub fn clearMiscFailures(comp: *Compilation) void { + comp.alloc_failure_occurred = false; for (comp.misc_failures.values()) |*value| { value.deinit(comp.gpa); } @@ -2533,8 +2535,10 @@ pub fn makeBinFileWritable(self: *Compilation) !void { return self.bin_file.makeWritable(); } +/// This function is temporally single-threaded. pub fn totalErrorCount(self: *Compilation) usize { - var total: usize = self.failed_c_objects.count() + self.misc_failures.count(); + var total: usize = self.failed_c_objects.count() + self.misc_failures.count() + + @boolToInt(self.alloc_failure_occurred); if (self.bin_file.options.module) |module| { total += module.failed_exports.count(); @@ -2591,6 +2595,7 @@ pub fn totalErrorCount(self: *Compilation) usize { return total; } +/// This function is temporally single-threaded. pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { var arena = std.heap.ArenaAllocator.init(self.gpa); errdefer arena.deinit(); @@ -2623,6 +2628,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { for (self.misc_failures.values()) |*value| { try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children); } + if (self.alloc_failure_occurred) { + try AllErrors.addPlain(&arena, &errors, "memory allocation failure"); + } if (self.bin_file.options.module) |module| { { var it = module.failed_files.iterator(); @@ -2737,9 +2745,15 @@ pub fn performAllTheWork( var embed_file_prog_node = main_progress_node.start("Detect @embedFile updates", comp.embed_file_work_queue.count); defer embed_file_prog_node.end(); + // +1 for the link step + var compiler_rt_prog_node = main_progress_node.start("compiler_rt", compiler_rt.sources.len + 1); + defer compiler_rt_prog_node.end(); + comp.work_queue_wait_group.reset(); defer comp.work_queue_wait_group.wait(); + const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; + { const astgen_frame = tracy.namedFrame("astgen"); defer astgen_frame.end(); @@ -2782,9 +2796,28 @@ pub fn performAllTheWork( comp, c_object, &c_obj_prog_node, &comp.work_queue_wait_group, }); } + + if (comp.job_queued_compiler_rt_lib) { + comp.job_queued_compiler_rt_lib = false; + + if (use_stage1) { + // stage1 LLVM backend uses the global context and thus cannot be used in + // a multi-threaded context. + buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib); + } else { + comp.work_queue_wait_group.start(); + try comp.thread_pool.spawn(workerBuildCompilerRtLib, .{ + comp, &compiler_rt_prog_node, &comp.work_queue_wait_group, + }); + } + } + + if (comp.job_queued_compiler_rt_obj) { + comp.job_queued_compiler_rt_obj = false; + buildCompilerRtOneShot(comp, .Obj, &comp.compiler_rt_obj); + } } - const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; if (!use_stage1) { const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls"); defer outdated_and_deleted_decls_frame.end(); @@ -2997,7 +3030,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { module.semaPkg(pkg) catch |err| switch (err) { error.CurrentWorkingDirectoryUnlinked, error.Unexpected, - => try comp.setMiscFailure( + => comp.lockAndSetMiscFailure( .analyze_pkg, "unexpected problem analyzing package '{s}'", .{pkg.root_src_path}, @@ -3012,7 +3045,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { glibc.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{ + comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{ @errorName(err), }); }; @@ -3023,7 +3056,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { glibc.buildSharedObjects(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .glibc_shared_objects, "unable to build glibc shared objects: {s}", .{@errorName(err)}, @@ -3036,7 +3069,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { musl.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .musl_crt_file, "unable to build musl CRT file: {s}", .{@errorName(err)}, @@ -3049,7 +3082,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { mingw.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .mingw_crt_file, "unable to build mingw-w64 CRT file: {s}", .{@errorName(err)}, @@ -3063,7 +3096,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { const link_lib = comp.bin_file.options.system_libs.keys()[index]; mingw.buildImportLib(comp, link_lib) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .windows_import_lib, "unable to generate DLL import .lib file: {s}", .{@errorName(err)}, @@ -3076,7 +3109,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libunwind.buildStaticLib(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libunwind, "unable to build libunwind: {s}", .{@errorName(err)}, @@ -3089,7 +3122,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libcxx.buildLibCXX(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libcxx, "unable to build libcxx: {s}", .{@errorName(err)}, @@ -3102,7 +3135,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libcxx.buildLibCXXABI(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libcxxabi, "unable to build libcxxabi: {s}", .{@errorName(err)}, @@ -3115,7 +3148,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { libtsan.buildTsan(comp) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .libtsan, "unable to build TSAN library: {s}", .{@errorName(err)}, @@ -3128,49 +3161,13 @@ fn processOneJob(comp: *Compilation, job: Job) !void { wasi_libc.buildCRTFile(comp, crt_file) catch |err| { // TODO Surface more error details. - try comp.setMiscFailure( + comp.lockAndSetMiscFailure( .wasi_libc_crt_file, "unable to build WASI libc CRT file: {s}", .{@errorName(err)}, ); }; }, - .compiler_rt_lib => { - const named_frame = tracy.namedFrame("compiler_rt_lib"); - defer named_frame.end(); - - compiler_rt.buildCompilerRtLib( - comp, - &comp.compiler_rt_lib, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; - }, - .compiler_rt_obj => { - const named_frame = tracy.namedFrame("compiler_rt_obj"); - defer named_frame.end(); - - comp.buildOutputFromZig( - "compiler_rt.zig", - .Obj, - &comp.compiler_rt_obj, - .compiler_rt, - ) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; - }, .libssp => { const named_frame = tracy.namedFrame("libssp"); defer named_frame.end(); @@ -3183,7 +3180,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( + else => comp.lockAndSetMiscFailure( .libssp, "unable to build libssp: {s}", .{@errorName(err)}, @@ -3202,7 +3199,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void { ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.SubCompilationFailed => return, // error reported already - else => try comp.setMiscFailure( + else => comp.lockAndSetMiscFailure( .zig_libc, "unable to build zig's multitarget libc: {s}", .{@errorName(err)}, @@ -3306,11 +3303,7 @@ fn workerUpdateBuiltinZigFile( comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{ dir_path, @errorName(err), - }) catch |oom| switch (oom) { - error.OutOfMemory => log.err("unable to write builtin.zig to {s}: {s}", .{ - dir_path, @errorName(err), - }), - }; + }); }; } @@ -3524,6 +3517,38 @@ fn workerUpdateCObject( }; } +fn buildCompilerRtOneShot( + comp: *Compilation, + output_mode: std.builtin.OutputMode, + out: *?CRTFile, +) void { + comp.buildOutputFromZig("compiler_rt.zig", output_mode, out, .compiler_rt) catch |err| switch (err) { + error.SubCompilationFailed => return, // error reported already + else => comp.lockAndSetMiscFailure( + .compiler_rt, + "unable to build compiler_rt: {s}", + .{@errorName(err)}, + ), + }; +} + +fn workerBuildCompilerRtLib( + comp: *Compilation, + progress_node: *std.Progress.Node, + wg: *WaitGroup, +) void { + defer wg.finish(); + + compiler_rt.buildCompilerRtLib(comp, progress_node) catch |err| switch (err) { + error.SubCompilationFailed => return, // error reported already + else => comp.lockAndSetMiscFailure( + .compiler_rt, + "unable to build compiler_rt: {s}", + .{@errorName(err)}, + ), + }; +} + fn reportRetryableCObjectError( comp: *Compilation, c_object: *CObject, @@ -4622,14 +4647,21 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { comp.bin_file.options.object_format != .c; } -fn setMiscFailure( +fn setAllocFailure(comp: *Compilation) void { + log.debug("memory allocation failure", .{}); + comp.alloc_failure_occurred = true; +} + +/// Assumes that Compilation mutex is locked. +/// See also `lockAndSetMiscFailure`. +pub fn setMiscFailure( comp: *Compilation, tag: MiscTask, comptime format: []const u8, args: anytype, -) Allocator.Error!void { - try comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1); - const msg = try std.fmt.allocPrint(comp.gpa, format, args); +) void { + comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1) catch return comp.setAllocFailure(); + const msg = std.fmt.allocPrint(comp.gpa, format, args) catch return comp.setAllocFailure(); const gop = comp.misc_failures.getOrPutAssumeCapacity(tag); if (gop.found_existing) { gop.value_ptr.deinit(comp.gpa); @@ -4637,6 +4669,19 @@ fn setMiscFailure( gop.value_ptr.* = .{ .msg = msg }; } +/// See also `setMiscFailure`. +pub fn lockAndSetMiscFailure( + comp: *Compilation, + tag: MiscTask, + comptime format: []const u8, + args: anytype, +) void { + comp.mutex.lock(); + defer comp.mutex.unlock(); + + return setMiscFailure(comp, tag, format, args); +} + pub fn dump_argv(argv: []const []const u8) void { for (argv[0 .. argv.len - 1]) |arg| { std.debug.print("{s} ", .{arg}); @@ -4896,7 +4941,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void { } } -pub fn buildOutputFromZig( +fn buildOutputFromZig( comp: *Compilation, src_basename: []const u8, output_mode: std.builtin.OutputMode, @@ -4913,15 +4958,7 @@ pub fn buildOutputFromZig( .root_src_path = src_basename, }; defer main_pkg.deinitTable(comp.gpa); - - const root_name = root_name: { - const basename = if (std.fs.path.dirname(src_basename)) |dirname| - src_basename[dirname.len + 1 ..] - else - src_basename; - const root_name = basename[0 .. basename.len - std.fs.path.extension(basename).len]; - break :root_name root_name; - }; + const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; const target = comp.getTarget(); const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{ .root_name = root_name, diff --git a/src/ThreadPool.zig b/src/ThreadPool.zig index 55e40ea287..7115adbddd 100644 --- a/src/ThreadPool.zig +++ b/src/ThreadPool.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const ThreadPool = @This(); +const WaitGroup = @import("WaitGroup.zig"); mutex: std.Thread.Mutex = .{}, cond: std.Thread.Condition = .{}, @@ -19,8 +20,8 @@ const RunProto = switch (builtin.zig_backend) { else => *const fn (*Runnable) void, }; -pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { - self.* = .{ +pub fn init(pool: *ThreadPool, allocator: std.mem.Allocator) !void { + pool.* = .{ .allocator = allocator, .threads = &[_]std.Thread{}, }; @@ -30,48 +31,48 @@ pub fn init(self: *ThreadPool, allocator: std.mem.Allocator) !void { } const thread_count = std.math.max(1, std.Thread.getCpuCount() catch 1); - self.threads = try allocator.alloc(std.Thread, thread_count); - errdefer allocator.free(self.threads); + pool.threads = try allocator.alloc(std.Thread, thread_count); + errdefer allocator.free(pool.threads); // kill and join any threads we spawned previously on error. var spawned: usize = 0; - errdefer self.join(spawned); + errdefer pool.join(spawned); - for (self.threads) |*thread| { - thread.* = try std.Thread.spawn(.{}, worker, .{self}); + for (pool.threads) |*thread| { + thread.* = try std.Thread.spawn(.{}, worker, .{pool}); spawned += 1; } } -pub fn deinit(self: *ThreadPool) void { - self.join(self.threads.len); // kill and join all threads. - self.* = undefined; +pub fn deinit(pool: *ThreadPool) void { + pool.join(pool.threads.len); // kill and join all threads. + pool.* = undefined; } -fn join(self: *ThreadPool, spawned: usize) void { +fn join(pool: *ThreadPool, spawned: usize) void { if (builtin.single_threaded) { return; } { - self.mutex.lock(); - defer self.mutex.unlock(); + pool.mutex.lock(); + defer pool.mutex.unlock(); // ensure future worker threads exit the dequeue loop - self.is_running = false; + pool.is_running = false; } // wake up any sleeping threads (this can be done outside the mutex) // then wait for all the threads we know are spawned to complete. - self.cond.broadcast(); - for (self.threads[0..spawned]) |thread| { + pool.cond.broadcast(); + for (pool.threads[0..spawned]) |thread| { thread.join(); } - self.allocator.free(self.threads); + pool.allocator.free(pool.threads); } -pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { +pub fn spawn(pool: *ThreadPool, comptime func: anytype, args: anytype) !void { if (builtin.single_threaded) { @call(.{}, func, args); return; @@ -98,41 +99,57 @@ pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void { }; { - self.mutex.lock(); - defer self.mutex.unlock(); + pool.mutex.lock(); + defer pool.mutex.unlock(); - const closure = try self.allocator.create(Closure); + const closure = try pool.allocator.create(Closure); closure.* = .{ .arguments = args, - .pool = self, + .pool = pool, }; - self.run_queue.prepend(&closure.run_node); + pool.run_queue.prepend(&closure.run_node); } // Notify waiting threads outside the lock to try and keep the critical section small. - self.cond.signal(); + pool.cond.signal(); } -fn worker(self: *ThreadPool) void { - self.mutex.lock(); - defer self.mutex.unlock(); +fn worker(pool: *ThreadPool) void { + pool.mutex.lock(); + defer pool.mutex.unlock(); while (true) { - while (self.run_queue.popFirst()) |run_node| { + while (pool.run_queue.popFirst()) |run_node| { // Temporarily unlock the mutex in order to execute the run_node - self.mutex.unlock(); - defer self.mutex.lock(); + pool.mutex.unlock(); + defer pool.mutex.lock(); const runFn = run_node.data.runFn; runFn(&run_node.data); } // Stop executing instead of waiting if the thread pool is no longer running. - if (self.is_running) { - self.cond.wait(&self.mutex); + if (pool.is_running) { + pool.cond.wait(&pool.mutex); } else { break; } } } + +pub fn waitAndWork(pool: *ThreadPool, wait_group: *WaitGroup) void { + while (!wait_group.isDone()) { + if (blk: { + pool.mutex.lock(); + defer pool.mutex.unlock(); + break :blk pool.run_queue.popFirst(); + }) |run_node| { + run_node.data.runFn(&run_node.data); + continue; + } + + wait_group.wait(); + return; + } +} diff --git a/src/WaitGroup.zig b/src/WaitGroup.zig index 860d0a8b4c..c8be6658db 100644 --- a/src/WaitGroup.zig +++ b/src/WaitGroup.zig @@ -37,3 +37,10 @@ pub fn reset(self: *WaitGroup) void { self.state.store(0, .Monotonic); self.event.reset(); } + +pub fn isDone(wg: *WaitGroup) bool { + const state = wg.state.load(.Acquire); + assert(state & is_waiting == 0); + + return (state / one_pending) == 0; +} diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 70276231ce..4e43f0be88 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -12,316 +12,393 @@ const Compilation = @import("Compilation.zig"); const CRTFile = Compilation.CRTFile; const LinkObject = Compilation.LinkObject; const Package = @import("Package.zig"); +const WaitGroup = @import("WaitGroup.zig"); -pub fn buildCompilerRtLib(comp: *Compilation, compiler_rt_lib: *?CRTFile) !void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - +pub fn buildCompilerRtLib(comp: *Compilation, progress_node: *std.Progress.Node) !void { var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); const target = comp.getTarget(); - // Use the global cache directory. - var cache_parent: Cache = .{ - .gpa = comp.gpa, - .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}), + const root_name = "compiler_rt"; + const basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target, + .output_mode = .Lib, + }); + + var link_objects: [sources.len]LinkObject = undefined; + var crt_files = [1]?CRTFile{null} ** sources.len; + defer deinitCrtFiles(comp, crt_files); + + { + var wg: WaitGroup = .{}; + defer comp.thread_pool.waitAndWork(&wg); + + for (sources) |source, i| { + wg.start(); + try comp.thread_pool.spawn(workerBuildObject, .{ + comp, progress_node, &wg, source, &crt_files[i], + }); + } + } + + for (link_objects) |*link_object, i| { + link_object.* = .{ + .path = crt_files[i].?.full_object_path, + }; + } + + var link_progress_node = progress_node.start("link", 0); + link_progress_node.activate(); + defer link_progress_node.end(); + + // TODO: This is extracted into a local variable to work around a stage1 miscompilation. + const emit_bin = Compilation.EmitLoc{ + .directory = null, // Put it in the cache directory. + .basename = basename, + }; + const sub_compilation = try Compilation.create(comp.gpa, .{ + .local_cache_directory = comp.global_cache_directory, + .global_cache_directory = comp.global_cache_directory, + .zig_lib_directory = comp.zig_lib_directory, + .cache_mode = .whole, + .target = target, + .root_name = root_name, + .main_pkg = null, + .output_mode = .Lib, + .link_mode = .Static, + .thread_pool = comp.thread_pool, + .libc_installation = comp.bin_file.options.libc_installation, + .emit_bin = emit_bin, + .optimize_mode = comp.compilerRtOptMode(), + .want_sanitize_c = false, + .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, + .want_valgrind = false, + .want_tsan = false, + .want_pic = comp.bin_file.options.pic, + .want_pie = comp.bin_file.options.pie, + .want_lto = comp.bin_file.options.lto, + .emit_h = null, + .strip = comp.compilerRtStrip(), + .is_native_os = comp.bin_file.options.is_native_os, + .is_native_abi = comp.bin_file.options.is_native_abi, + .self_exe_path = comp.self_exe_path, + .link_objects = &link_objects, + .verbose_cc = comp.verbose_cc, + .verbose_link = comp.bin_file.options.verbose_link, + .verbose_air = comp.verbose_air, + .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_cimport = comp.verbose_cimport, + .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, + .clang_passthrough_mode = comp.clang_passthrough_mode, + .skip_linker_dependencies = true, + .parent_compilation_link_libc = comp.bin_file.options.link_libc, + }); + defer sub_compilation.destroy(); + + try sub_compilation.updateSubCompilation(); + + assert(comp.compiler_rt_lib == null); + comp.compiler_rt_lib = .{ + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.options.emit.?.sub_path, + }), + .lock = sub_compilation.bin_file.toOwnedLock(), }; - defer cache_parent.manifest_dir.close(); +} - var cache = cache_parent.obtain(); - defer cache.deinit(); +fn deinitCrtFiles(comp: *Compilation, crt_files: [sources.len]?CRTFile) void { + const gpa = comp.gpa; - cache.hash.add(sources.len); - for (sources) |source| { - const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{source}); - _ = try cache.addFile(full_path, null); + for (crt_files) |opt_crt_file| { + var crt_file = opt_crt_file orelse continue; + crt_file.deinit(gpa); } +} - cache.hash.addBytes(build_options.version); - cache.hash.addBytes(comp.zig_lib_directory.path orelse "."); - cache.hash.add(target.cpu.arch); - cache.hash.add(target.os.tag); - cache.hash.add(target.abi); +fn workerBuildObject( + comp: *Compilation, + progress_node: *std.Progress.Node, + wg: *WaitGroup, + src_basename: []const u8, + out: *?CRTFile, +) void { + defer wg.finish(); - const hit = try cache.hit(); - const digest = cache.final(); - const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); + var obj_progress_node = progress_node.start(src_basename, 0); + obj_progress_node.activate(); + defer obj_progress_node.end(); - var o_directory: Compilation.Directory = .{ - .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}), - .path = try std.fs.path.join(arena, &[_][]const u8{ comp.global_cache_directory.path.?, o_sub_path }), + buildObject(comp, src_basename, out) catch |err| switch (err) { + error.SubCompilationFailed => return, // error reported already + else => comp.lockAndSetMiscFailure( + .compiler_rt, + "unable to build compiler_rt: {s}", + .{@errorName(err)}, + ), }; - defer o_directory.handle.close(); +} - const ok_basename = "ok"; - const actual_hit = if (hit) blk: { - o_directory.handle.access(ok_basename, .{}) catch |err| switch (err) { - error.FileNotFound => break :blk false, - else => |e| return e, - }; - break :blk true; - } else false; +fn buildObject(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void { + const gpa = comp.gpa; - const root_name = "compiler_rt"; - const basename = try std.zig.binNameAlloc(arena, .{ + var root_src_path_buf: [64]u8 = undefined; + const root_src_path = std.fmt.bufPrint( + &root_src_path_buf, + "compiler_rt" ++ std.fs.path.sep_str ++ "{s}", + .{src_basename}, + ) catch unreachable; + + var main_pkg: Package = .{ + .root_src_directory = comp.zig_lib_directory, + .root_src_path = root_src_path, + }; + defer main_pkg.deinitTable(gpa); + const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; + const target = comp.getTarget(); + const output_mode: std.builtin.OutputMode = .Obj; + const bin_basename = try std.zig.binNameAlloc(gpa, .{ .root_name = root_name, .target = target, - .output_mode = .Lib, + .output_mode = output_mode, }); + defer gpa.free(bin_basename); - if (!actual_hit) { - var progress: std.Progress = .{ .dont_print_on_dumb = true }; - var progress_node = progress.start("Compile Compiler-RT", sources.len + 1); - defer progress_node.end(); - if (comp.color == .off) progress.terminal = null; - - progress_node.activate(); + const emit_bin = Compilation.EmitLoc{ + .directory = null, // Put it in the cache directory. + .basename = bin_basename, + }; + const sub_compilation = try Compilation.create(gpa, .{ + .global_cache_directory = comp.global_cache_directory, + .local_cache_directory = comp.global_cache_directory, + .zig_lib_directory = comp.zig_lib_directory, + .cache_mode = .whole, + .target = target, + .root_name = root_name, + .main_pkg = &main_pkg, + .output_mode = output_mode, + .thread_pool = comp.thread_pool, + .libc_installation = comp.bin_file.options.libc_installation, + .emit_bin = emit_bin, + .optimize_mode = comp.compilerRtOptMode(), + .link_mode = .Static, + .want_sanitize_c = false, + .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, + .want_valgrind = false, + .want_tsan = false, + .want_pic = comp.bin_file.options.pic, + .want_pie = comp.bin_file.options.pie, + .emit_h = null, + .strip = comp.compilerRtStrip(), + .is_native_os = comp.bin_file.options.is_native_os, + .is_native_abi = comp.bin_file.options.is_native_abi, + .self_exe_path = comp.self_exe_path, + .verbose_cc = comp.verbose_cc, + .verbose_link = comp.bin_file.options.verbose_link, + .verbose_air = comp.verbose_air, + .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_cimport = comp.verbose_cimport, + .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, + .clang_passthrough_mode = comp.clang_passthrough_mode, + .skip_linker_dependencies = true, + .parent_compilation_link_libc = comp.bin_file.options.link_libc, + }); + defer sub_compilation.destroy(); - var link_objects: [sources.len]LinkObject = undefined; - for (sources) |source, i| { - var obj_progress_node = progress_node.start(source, 0); - obj_progress_node.activate(); - defer obj_progress_node.end(); + try sub_compilation.update(); + // Look for compilation errors in this sub_compilation. + var keep_errors = false; + var errors = try sub_compilation.getAllErrorsAlloc(); + defer if (!keep_errors) errors.deinit(sub_compilation.gpa); - var tmp_crt_file: ?CRTFile = null; - defer if (tmp_crt_file) |*crt| crt.deinit(comp.gpa); - try comp.buildOutputFromZig(source, .Obj, &tmp_crt_file, .compiler_rt); - link_objects[i] = .{ - .path = try arena.dupe(u8, tmp_crt_file.?.full_object_path), - .must_link = true, - }; - } + if (errors.list.len != 0) { + const misc_task_tag: Compilation.MiscTask = .compiler_rt; - var lib_progress_node = progress_node.start(root_name, 0); - lib_progress_node.activate(); - defer lib_progress_node.end(); + comp.mutex.lock(); + defer comp.mutex.unlock(); - // TODO: This is extracted into a local variable to work around a stage1 miscompilation. - const emit_bin = Compilation.EmitLoc{ - .directory = o_directory, // Put it in the cache directory. - .basename = basename, - }; - const sub_compilation = try Compilation.create(comp.gpa, .{ - .local_cache_directory = comp.global_cache_directory, - .global_cache_directory = comp.global_cache_directory, - .zig_lib_directory = comp.zig_lib_directory, - .cache_mode = .whole, - .target = target, - .root_name = root_name, - .main_pkg = null, - .output_mode = .Lib, - .link_mode = .Static, - .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, - .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .want_sanitize_c = false, - .want_stack_check = false, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = comp.bin_file.options.pie, - .want_lto = comp.bin_file.options.lto, - .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, - .link_objects = &link_objects, - .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, - .parent_compilation_link_libc = comp.bin_file.options.link_libc, + try comp.misc_failures.ensureUnusedCapacity(gpa, 1); + comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{ + .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {s} failed", .{ + @tagName(misc_task_tag), + }), + .children = errors, }); - defer sub_compilation.destroy(); - - try sub_compilation.updateSubCompilation(); - - if (o_directory.handle.createFile(ok_basename, .{})) |file| { - file.close(); - } else |err| { - std.log.warn("compiler-rt lib: failed to mark completion: {s}", .{@errorName(err)}); - } + keep_errors = true; + return error.SubCompilationFailed; } - try cache.writeManifest(); - - assert(compiler_rt_lib.* == null); - compiler_rt_lib.* = .{ - .full_object_path = try std.fs.path.join(comp.gpa, &[_][]const u8{ - comp.global_cache_directory.path.?, - o_sub_path, - basename, + assert(out.* == null); + out.* = Compilation.CRTFile{ + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(gpa, &[_][]const u8{ + sub_compilation.bin_file.options.emit.?.sub_path, }), - .lock = cache.toOwnedLock(), + .lock = sub_compilation.bin_file.toOwnedLock(), }; } -const sources = &[_][]const u8{ - "compiler_rt/absvdi2.zig", - "compiler_rt/absvsi2.zig", - "compiler_rt/absvti2.zig", - "compiler_rt/adddf3.zig", - "compiler_rt/addo.zig", - "compiler_rt/addsf3.zig", - "compiler_rt/addtf3.zig", - "compiler_rt/addxf3.zig", - "compiler_rt/arm.zig", - "compiler_rt/atomics.zig", - "compiler_rt/aulldiv.zig", - "compiler_rt/aullrem.zig", - "compiler_rt/bswap.zig", - "compiler_rt/ceil.zig", - "compiler_rt/clear_cache.zig", - "compiler_rt/cmp.zig", - "compiler_rt/cmpdf2.zig", - "compiler_rt/cmpsf2.zig", - "compiler_rt/cmptf2.zig", - "compiler_rt/cmpxf2.zig", - "compiler_rt/cos.zig", - "compiler_rt/count0bits.zig", - "compiler_rt/divdf3.zig", - "compiler_rt/divsf3.zig", - "compiler_rt/divtf3.zig", - "compiler_rt/divti3.zig", - "compiler_rt/divxf3.zig", - "compiler_rt/emutls.zig", - "compiler_rt/exp.zig", - "compiler_rt/exp2.zig", - "compiler_rt/extenddftf2.zig", - "compiler_rt/extenddfxf2.zig", - "compiler_rt/extendhfsf2.zig", - "compiler_rt/extendhftf2.zig", - "compiler_rt/extendhfxf2.zig", - "compiler_rt/extendsfdf2.zig", - "compiler_rt/extendsftf2.zig", - "compiler_rt/extendsfxf2.zig", - "compiler_rt/extendxftf2.zig", - "compiler_rt/fabs.zig", - "compiler_rt/fixdfdi.zig", - "compiler_rt/fixdfsi.zig", - "compiler_rt/fixdfti.zig", - "compiler_rt/fixhfdi.zig", - "compiler_rt/fixhfsi.zig", - "compiler_rt/fixhfti.zig", - "compiler_rt/fixsfdi.zig", - "compiler_rt/fixsfsi.zig", - "compiler_rt/fixsfti.zig", - "compiler_rt/fixtfdi.zig", - "compiler_rt/fixtfsi.zig", - "compiler_rt/fixtfti.zig", - "compiler_rt/fixunsdfdi.zig", - "compiler_rt/fixunsdfsi.zig", - "compiler_rt/fixunsdfti.zig", - "compiler_rt/fixunshfdi.zig", - "compiler_rt/fixunshfsi.zig", - "compiler_rt/fixunshfti.zig", - "compiler_rt/fixunssfdi.zig", - "compiler_rt/fixunssfsi.zig", - "compiler_rt/fixunssfti.zig", - "compiler_rt/fixunstfdi.zig", - "compiler_rt/fixunstfsi.zig", - "compiler_rt/fixunstfti.zig", - "compiler_rt/fixunsxfdi.zig", - "compiler_rt/fixunsxfsi.zig", - "compiler_rt/fixunsxfti.zig", - "compiler_rt/fixxfdi.zig", - "compiler_rt/fixxfsi.zig", - "compiler_rt/fixxfti.zig", - "compiler_rt/floatdidf.zig", - "compiler_rt/floatdihf.zig", - "compiler_rt/floatdisf.zig", - "compiler_rt/floatditf.zig", - "compiler_rt/floatdixf.zig", - "compiler_rt/floatsidf.zig", - "compiler_rt/floatsihf.zig", - "compiler_rt/floatsisf.zig", - "compiler_rt/floatsitf.zig", - "compiler_rt/floatsixf.zig", - "compiler_rt/floattidf.zig", - "compiler_rt/floattihf.zig", - "compiler_rt/floattisf.zig", - "compiler_rt/floattitf.zig", - "compiler_rt/floattixf.zig", - "compiler_rt/floatundidf.zig", - "compiler_rt/floatundihf.zig", - "compiler_rt/floatundisf.zig", - "compiler_rt/floatunditf.zig", - "compiler_rt/floatundixf.zig", - "compiler_rt/floatunsidf.zig", - "compiler_rt/floatunsihf.zig", - "compiler_rt/floatunsisf.zig", - "compiler_rt/floatunsitf.zig", - "compiler_rt/floatunsixf.zig", - "compiler_rt/floatuntidf.zig", - "compiler_rt/floatuntihf.zig", - "compiler_rt/floatuntisf.zig", - "compiler_rt/floatuntitf.zig", - "compiler_rt/floatuntixf.zig", - "compiler_rt/floor.zig", - "compiler_rt/fma.zig", - "compiler_rt/fmax.zig", - "compiler_rt/fmin.zig", - "compiler_rt/fmod.zig", - "compiler_rt/gedf2.zig", - "compiler_rt/gesf2.zig", - "compiler_rt/getf2.zig", - "compiler_rt/gexf2.zig", - "compiler_rt/int.zig", - "compiler_rt/log.zig", - "compiler_rt/log10.zig", - "compiler_rt/log2.zig", - "compiler_rt/modti3.zig", - "compiler_rt/muldf3.zig", - "compiler_rt/muldi3.zig", - "compiler_rt/mulf3.zig", - "compiler_rt/mulo.zig", - "compiler_rt/mulsf3.zig", - "compiler_rt/multf3.zig", - "compiler_rt/multi3.zig", - "compiler_rt/mulxf3.zig", - "compiler_rt/negXf2.zig", - "compiler_rt/negXi2.zig", - "compiler_rt/negv.zig", - "compiler_rt/os_version_check.zig", - "compiler_rt/parity.zig", - "compiler_rt/popcount.zig", - "compiler_rt/round.zig", - "compiler_rt/shift.zig", - "compiler_rt/sin.zig", - "compiler_rt/sincos.zig", - "compiler_rt/sqrt.zig", - "compiler_rt/stack_probe.zig", - "compiler_rt/subdf3.zig", - "compiler_rt/subo.zig", - "compiler_rt/subsf3.zig", - "compiler_rt/subtf3.zig", - "compiler_rt/subxf3.zig", - "compiler_rt/tan.zig", - "compiler_rt/trunc.zig", - "compiler_rt/truncdfhf2.zig", - "compiler_rt/truncdfsf2.zig", - "compiler_rt/truncsfhf2.zig", - "compiler_rt/trunctfdf2.zig", - "compiler_rt/trunctfhf2.zig", - "compiler_rt/trunctfsf2.zig", - "compiler_rt/trunctfxf2.zig", - "compiler_rt/truncxfdf2.zig", - "compiler_rt/truncxfhf2.zig", - "compiler_rt/truncxfsf2.zig", - "compiler_rt/udivmodti4.zig", - "compiler_rt/udivti3.zig", - "compiler_rt/umodti3.zig", - "compiler_rt/unorddf2.zig", - "compiler_rt/unordsf2.zig", - "compiler_rt/unordtf2.zig", +pub const sources = &[_][]const u8{ + "absvdi2.zig", + "absvsi2.zig", + "absvti2.zig", + "adddf3.zig", + "addo.zig", + "addsf3.zig", + "addtf3.zig", + "addxf3.zig", + "arm.zig", + "atomics.zig", + "aulldiv.zig", + "aullrem.zig", + "bswap.zig", + "ceil.zig", + "clear_cache.zig", + "cmp.zig", + "cmpdf2.zig", + "cmpsf2.zig", + "cmptf2.zig", + "cmpxf2.zig", + "cos.zig", + "count0bits.zig", + "divdf3.zig", + "divsf3.zig", + "divtf3.zig", + "divti3.zig", + "divxf3.zig", + "emutls.zig", + "exp.zig", + "exp2.zig", + "extenddftf2.zig", + "extenddfxf2.zig", + "extendhfsf2.zig", + "extendhftf2.zig", + "extendhfxf2.zig", + "extendsfdf2.zig", + "extendsftf2.zig", + "extendsfxf2.zig", + "extendxftf2.zig", + "fabs.zig", + "fixdfdi.zig", + "fixdfsi.zig", + "fixdfti.zig", + "fixhfdi.zig", + "fixhfsi.zig", + "fixhfti.zig", + "fixsfdi.zig", + "fixsfsi.zig", + "fixsfti.zig", + "fixtfdi.zig", + "fixtfsi.zig", + "fixtfti.zig", + "fixunsdfdi.zig", + "fixunsdfsi.zig", + "fixunsdfti.zig", + "fixunshfdi.zig", + "fixunshfsi.zig", + "fixunshfti.zig", + "fixunssfdi.zig", + "fixunssfsi.zig", + "fixunssfti.zig", + "fixunstfdi.zig", + "fixunstfsi.zig", + "fixunstfti.zig", + "fixunsxfdi.zig", + "fixunsxfsi.zig", + "fixunsxfti.zig", + "fixxfdi.zig", + "fixxfsi.zig", + "fixxfti.zig", + "floatdidf.zig", + "floatdihf.zig", + "floatdisf.zig", + "floatditf.zig", + "floatdixf.zig", + "floatsidf.zig", + "floatsihf.zig", + "floatsisf.zig", + "floatsitf.zig", + "floatsixf.zig", + "floattidf.zig", + "floattihf.zig", + "floattisf.zig", + "floattitf.zig", + "floattixf.zig", + "floatundidf.zig", + "floatundihf.zig", + "floatundisf.zig", + "floatunditf.zig", + "floatundixf.zig", + "floatunsidf.zig", + "floatunsihf.zig", + "floatunsisf.zig", + "floatunsitf.zig", + "floatunsixf.zig", + "floatuntidf.zig", + "floatuntihf.zig", + "floatuntisf.zig", + "floatuntitf.zig", + "floatuntixf.zig", + "floor.zig", + "fma.zig", + "fmax.zig", + "fmin.zig", + "fmod.zig", + "gedf2.zig", + "gesf2.zig", + "getf2.zig", + "gexf2.zig", + "int.zig", + "log.zig", + "log10.zig", + "log2.zig", + "modti3.zig", + "muldf3.zig", + "muldi3.zig", + "mulf3.zig", + "mulo.zig", + "mulsf3.zig", + "multf3.zig", + "multi3.zig", + "mulxf3.zig", + "negXf2.zig", + "negXi2.zig", + "negv.zig", + "os_version_check.zig", + "parity.zig", + "popcount.zig", + "round.zig", + "shift.zig", + "sin.zig", + "sincos.zig", + "sqrt.zig", + "stack_probe.zig", + "subdf3.zig", + "subo.zig", + "subsf3.zig", + "subtf3.zig", + "subxf3.zig", + "tan.zig", + "trunc.zig", + "truncdfhf2.zig", + "truncdfsf2.zig", + "truncsfhf2.zig", + "trunctfdf2.zig", + "trunctfhf2.zig", + "trunctfsf2.zig", + "trunctfxf2.zig", + "truncxfdf2.zig", + "truncxfhf2.zig", + "truncxfsf2.zig", + "udivmodti4.zig", + "udivti3.zig", + "umodti3.zig", + "unorddf2.zig", + "unordsf2.zig", + "unordtf2.zig", }; -- cgit v1.2.3 From e798a3a7796892427ac4561839a35286108bbf6c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 16 Jun 2022 20:51:15 -0700 Subject: compiler-rt: disable separate compilation units --- src/Compilation.zig | 4 +++- src/compiler_rt.zig | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Compilation.zig b/src/Compilation.zig index 65a2ad92b4..89e54b598f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2800,7 +2800,9 @@ pub fn performAllTheWork( if (comp.job_queued_compiler_rt_lib) { comp.job_queued_compiler_rt_lib = false; - if (use_stage1) { + // I have disabled the multi-threaded compiler-rt for now until + // the threading deadlock is resolved. + if (use_stage1 or true) { // stage1 LLVM backend uses the global context and thus cannot be used in // a multi-threaded context. buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib); diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig index 4e43f0be88..185ebf6b16 100644 --- a/src/compiler_rt.zig +++ b/src/compiler_rt.zig @@ -69,6 +69,7 @@ pub fn buildCompilerRtLib(comp: *Compilation, progress_node: *std.Progress.Node) .main_pkg = null, .output_mode = .Lib, .link_mode = .Static, + .function_sections = true, .thread_pool = comp.thread_pool, .libc_installation = comp.bin_file.options.libc_installation, .emit_bin = emit_bin, @@ -186,6 +187,7 @@ fn buildObject(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !vo .emit_bin = emit_bin, .optimize_mode = comp.compilerRtOptMode(), .link_mode = .Static, + .function_sections = true, .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, -- cgit v1.2.3 From e4092d44426a471ee6097fae24069c72cffdc22a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 17 Jun 2022 18:34:11 -0700 Subject: stage2: rip out multi-compilation-unit compiler-rt After doing performance testing, it seems that multi-compilation-unit compiler-rt did not bring the performance improvements that we expected it to. The idea is that it makes linking faster, however, it incurred a cost in the frontend that was not offset by any gains in linking. Furthermore, the single-object compiler-rt (with -ffunction-sections and --gc-sections) ends up being fewer bytes on disk and so it's actually the same or faster linking speed than the multi-compilation-unit version. So we are planning to keep using single-compilation-unit compiler-rt for the foreseeable future, but may experiment with this again in the future, in which case this commit can be reverted. --- CMakeLists.txt | 1 - src/Compilation.zig | 54 ++----- src/compiler_rt.zig | 406 ---------------------------------------------------- 3 files changed, 10 insertions(+), 451 deletions(-) delete mode 100644 src/compiler_rt.zig (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ba727f09e..29f521c789 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -735,7 +735,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/codegen/c.zig" "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig" "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig" - "${CMAKE_SOURCE_DIR}/src/compiler_rt.zig" "${CMAKE_SOURCE_DIR}/src/glibc.zig" "${CMAKE_SOURCE_DIR}/src/introspect.zig" "${CMAKE_SOURCE_DIR}/src/libc_installation.zig" diff --git a/src/Compilation.zig b/src/Compilation.zig index 89e54b598f..2646da2f6f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -23,7 +23,6 @@ const mingw = @import("mingw.zig"); const libunwind = @import("libunwind.zig"); const libcxx = @import("libcxx.zig"); const wasi_libc = @import("wasi_libc.zig"); -const compiler_rt = @import("compiler_rt.zig"); const fatal = @import("main.zig").fatal; const clangMain = @import("main.zig").clangMain; const Module = @import("Module.zig"); @@ -2745,10 +2744,6 @@ pub fn performAllTheWork( var embed_file_prog_node = main_progress_node.start("Detect @embedFile updates", comp.embed_file_work_queue.count); defer embed_file_prog_node.end(); - // +1 for the link step - var compiler_rt_prog_node = main_progress_node.start("compiler_rt", compiler_rt.sources.len + 1); - defer compiler_rt_prog_node.end(); - comp.work_queue_wait_group.reset(); defer comp.work_queue_wait_group.wait(); @@ -2796,28 +2791,6 @@ pub fn performAllTheWork( comp, c_object, &c_obj_prog_node, &comp.work_queue_wait_group, }); } - - if (comp.job_queued_compiler_rt_lib) { - comp.job_queued_compiler_rt_lib = false; - - // I have disabled the multi-threaded compiler-rt for now until - // the threading deadlock is resolved. - if (use_stage1 or true) { - // stage1 LLVM backend uses the global context and thus cannot be used in - // a multi-threaded context. - buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib); - } else { - comp.work_queue_wait_group.start(); - try comp.thread_pool.spawn(workerBuildCompilerRtLib, .{ - comp, &compiler_rt_prog_node, &comp.work_queue_wait_group, - }); - } - } - - if (comp.job_queued_compiler_rt_obj) { - comp.job_queued_compiler_rt_obj = false; - buildCompilerRtOneShot(comp, .Obj, &comp.compiler_rt_obj); - } } if (!use_stage1) { @@ -2862,6 +2835,16 @@ pub fn performAllTheWork( } break; } + + if (comp.job_queued_compiler_rt_lib) { + comp.job_queued_compiler_rt_lib = false; + buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib); + } + + if (comp.job_queued_compiler_rt_obj) { + comp.job_queued_compiler_rt_obj = false; + buildCompilerRtOneShot(comp, .Obj, &comp.compiler_rt_obj); + } } fn processOneJob(comp: *Compilation, job: Job) !void { @@ -3534,23 +3517,6 @@ fn buildCompilerRtOneShot( }; } -fn workerBuildCompilerRtLib( - comp: *Compilation, - progress_node: *std.Progress.Node, - wg: *WaitGroup, -) void { - defer wg.finish(); - - compiler_rt.buildCompilerRtLib(comp, progress_node) catch |err| switch (err) { - error.SubCompilationFailed => return, // error reported already - else => comp.lockAndSetMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; -} - fn reportRetryableCObjectError( comp: *Compilation, c_object: *CObject, diff --git a/src/compiler_rt.zig b/src/compiler_rt.zig deleted file mode 100644 index 185ebf6b16..0000000000 --- a/src/compiler_rt.zig +++ /dev/null @@ -1,406 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const build_options = @import("build_options"); -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; -const mem = std.mem; -const tracy = @import("tracy.zig"); -const trace = tracy.trace; - -const Cache = @import("Cache.zig"); -const Compilation = @import("Compilation.zig"); -const CRTFile = Compilation.CRTFile; -const LinkObject = Compilation.LinkObject; -const Package = @import("Package.zig"); -const WaitGroup = @import("WaitGroup.zig"); - -pub fn buildCompilerRtLib(comp: *Compilation, progress_node: *std.Progress.Node) !void { - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - const target = comp.getTarget(); - - const root_name = "compiler_rt"; - const basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = target, - .output_mode = .Lib, - }); - - var link_objects: [sources.len]LinkObject = undefined; - var crt_files = [1]?CRTFile{null} ** sources.len; - defer deinitCrtFiles(comp, crt_files); - - { - var wg: WaitGroup = .{}; - defer comp.thread_pool.waitAndWork(&wg); - - for (sources) |source, i| { - wg.start(); - try comp.thread_pool.spawn(workerBuildObject, .{ - comp, progress_node, &wg, source, &crt_files[i], - }); - } - } - - for (link_objects) |*link_object, i| { - link_object.* = .{ - .path = crt_files[i].?.full_object_path, - }; - } - - var link_progress_node = progress_node.start("link", 0); - link_progress_node.activate(); - defer link_progress_node.end(); - - // TODO: This is extracted into a local variable to work around a stage1 miscompilation. - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; - const sub_compilation = try Compilation.create(comp.gpa, .{ - .local_cache_directory = comp.global_cache_directory, - .global_cache_directory = comp.global_cache_directory, - .zig_lib_directory = comp.zig_lib_directory, - .cache_mode = .whole, - .target = target, - .root_name = root_name, - .main_pkg = null, - .output_mode = .Lib, - .link_mode = .Static, - .function_sections = true, - .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, - .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .want_sanitize_c = false, - .want_stack_check = false, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = comp.bin_file.options.pie, - .want_lto = comp.bin_file.options.lto, - .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, - .link_objects = &link_objects, - .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, - .parent_compilation_link_libc = comp.bin_file.options.link_libc, - }); - defer sub_compilation.destroy(); - - try sub_compilation.updateSubCompilation(); - - assert(comp.compiler_rt_lib == null); - comp.compiler_rt_lib = .{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, - }), - .lock = sub_compilation.bin_file.toOwnedLock(), - }; -} - -fn deinitCrtFiles(comp: *Compilation, crt_files: [sources.len]?CRTFile) void { - const gpa = comp.gpa; - - for (crt_files) |opt_crt_file| { - var crt_file = opt_crt_file orelse continue; - crt_file.deinit(gpa); - } -} - -fn workerBuildObject( - comp: *Compilation, - progress_node: *std.Progress.Node, - wg: *WaitGroup, - src_basename: []const u8, - out: *?CRTFile, -) void { - defer wg.finish(); - - var obj_progress_node = progress_node.start(src_basename, 0); - obj_progress_node.activate(); - defer obj_progress_node.end(); - - buildObject(comp, src_basename, out) catch |err| switch (err) { - error.SubCompilationFailed => return, // error reported already - else => comp.lockAndSetMiscFailure( - .compiler_rt, - "unable to build compiler_rt: {s}", - .{@errorName(err)}, - ), - }; -} - -fn buildObject(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void { - const gpa = comp.gpa; - - var root_src_path_buf: [64]u8 = undefined; - const root_src_path = std.fmt.bufPrint( - &root_src_path_buf, - "compiler_rt" ++ std.fs.path.sep_str ++ "{s}", - .{src_basename}, - ) catch unreachable; - - var main_pkg: Package = .{ - .root_src_directory = comp.zig_lib_directory, - .root_src_path = root_src_path, - }; - defer main_pkg.deinitTable(gpa); - const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; - const target = comp.getTarget(); - const output_mode: std.builtin.OutputMode = .Obj; - const bin_basename = try std.zig.binNameAlloc(gpa, .{ - .root_name = root_name, - .target = target, - .output_mode = output_mode, - }); - defer gpa.free(bin_basename); - - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = bin_basename, - }; - const sub_compilation = try Compilation.create(gpa, .{ - .global_cache_directory = comp.global_cache_directory, - .local_cache_directory = comp.global_cache_directory, - .zig_lib_directory = comp.zig_lib_directory, - .cache_mode = .whole, - .target = target, - .root_name = root_name, - .main_pkg = &main_pkg, - .output_mode = output_mode, - .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, - .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .link_mode = .Static, - .function_sections = true, - .want_sanitize_c = false, - .want_stack_check = false, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = comp.bin_file.options.pie, - .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, - .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, - .parent_compilation_link_libc = comp.bin_file.options.link_libc, - }); - defer sub_compilation.destroy(); - - try sub_compilation.update(); - // Look for compilation errors in this sub_compilation. - var keep_errors = false; - var errors = try sub_compilation.getAllErrorsAlloc(); - defer if (!keep_errors) errors.deinit(sub_compilation.gpa); - - if (errors.list.len != 0) { - const misc_task_tag: Compilation.MiscTask = .compiler_rt; - - comp.mutex.lock(); - defer comp.mutex.unlock(); - - try comp.misc_failures.ensureUnusedCapacity(gpa, 1); - comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{ - .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {s} failed", .{ - @tagName(misc_task_tag), - }), - .children = errors, - }); - keep_errors = true; - return error.SubCompilationFailed; - } - - assert(out.* == null); - out.* = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, - }), - .lock = sub_compilation.bin_file.toOwnedLock(), - }; -} - -pub const sources = &[_][]const u8{ - "absvdi2.zig", - "absvsi2.zig", - "absvti2.zig", - "adddf3.zig", - "addo.zig", - "addsf3.zig", - "addtf3.zig", - "addxf3.zig", - "arm.zig", - "atomics.zig", - "aulldiv.zig", - "aullrem.zig", - "bswap.zig", - "ceil.zig", - "clear_cache.zig", - "cmp.zig", - "cmpdf2.zig", - "cmpsf2.zig", - "cmptf2.zig", - "cmpxf2.zig", - "cos.zig", - "count0bits.zig", - "divdf3.zig", - "divsf3.zig", - "divtf3.zig", - "divti3.zig", - "divxf3.zig", - "emutls.zig", - "exp.zig", - "exp2.zig", - "extenddftf2.zig", - "extenddfxf2.zig", - "extendhfsf2.zig", - "extendhftf2.zig", - "extendhfxf2.zig", - "extendsfdf2.zig", - "extendsftf2.zig", - "extendsfxf2.zig", - "extendxftf2.zig", - "fabs.zig", - "fixdfdi.zig", - "fixdfsi.zig", - "fixdfti.zig", - "fixhfdi.zig", - "fixhfsi.zig", - "fixhfti.zig", - "fixsfdi.zig", - "fixsfsi.zig", - "fixsfti.zig", - "fixtfdi.zig", - "fixtfsi.zig", - "fixtfti.zig", - "fixunsdfdi.zig", - "fixunsdfsi.zig", - "fixunsdfti.zig", - "fixunshfdi.zig", - "fixunshfsi.zig", - "fixunshfti.zig", - "fixunssfdi.zig", - "fixunssfsi.zig", - "fixunssfti.zig", - "fixunstfdi.zig", - "fixunstfsi.zig", - "fixunstfti.zig", - "fixunsxfdi.zig", - "fixunsxfsi.zig", - "fixunsxfti.zig", - "fixxfdi.zig", - "fixxfsi.zig", - "fixxfti.zig", - "floatdidf.zig", - "floatdihf.zig", - "floatdisf.zig", - "floatditf.zig", - "floatdixf.zig", - "floatsidf.zig", - "floatsihf.zig", - "floatsisf.zig", - "floatsitf.zig", - "floatsixf.zig", - "floattidf.zig", - "floattihf.zig", - "floattisf.zig", - "floattitf.zig", - "floattixf.zig", - "floatundidf.zig", - "floatundihf.zig", - "floatundisf.zig", - "floatunditf.zig", - "floatundixf.zig", - "floatunsidf.zig", - "floatunsihf.zig", - "floatunsisf.zig", - "floatunsitf.zig", - "floatunsixf.zig", - "floatuntidf.zig", - "floatuntihf.zig", - "floatuntisf.zig", - "floatuntitf.zig", - "floatuntixf.zig", - "floor.zig", - "fma.zig", - "fmax.zig", - "fmin.zig", - "fmod.zig", - "gedf2.zig", - "gesf2.zig", - "getf2.zig", - "gexf2.zig", - "int.zig", - "log.zig", - "log10.zig", - "log2.zig", - "modti3.zig", - "muldf3.zig", - "muldi3.zig", - "mulf3.zig", - "mulo.zig", - "mulsf3.zig", - "multf3.zig", - "multi3.zig", - "mulxf3.zig", - "negXf2.zig", - "negXi2.zig", - "negv.zig", - "os_version_check.zig", - "parity.zig", - "popcount.zig", - "round.zig", - "shift.zig", - "sin.zig", - "sincos.zig", - "sqrt.zig", - "stack_probe.zig", - "subdf3.zig", - "subo.zig", - "subsf3.zig", - "subtf3.zig", - "subxf3.zig", - "tan.zig", - "trunc.zig", - "truncdfhf2.zig", - "truncdfsf2.zig", - "truncsfhf2.zig", - "trunctfdf2.zig", - "trunctfhf2.zig", - "trunctfsf2.zig", - "trunctfxf2.zig", - "truncxfdf2.zig", - "truncxfhf2.zig", - "truncxfsf2.zig", - "udivmodti4.zig", - "udivti3.zig", - "umodti3.zig", - "unorddf2.zig", - "unordsf2.zig", - "unordtf2.zig", -}; -- cgit v1.2.3 From 091238254e75253597e12ee381a3197751d61973 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 18 Jun 2022 22:55:55 +0200 Subject: macho: return from flushModule if building object for static lib --- src/link/MachO.zig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 44d763289a..c71007157a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -451,6 +451,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No llvm_object.destroy(self.base.allocator); self.llvm_object = null; + + if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { + return; + } } } -- cgit v1.2.3